Android camera用来拍照和拍摄视频的先看一下最后实现的效果图

            最后的效果图

一、准备

在你的应用程序上使用android拍照设备,需要考虑以下几个方面

1. 是否是一定需要camera

如果需要,那么就无法安装在没有摄像头的设备。

需要在mainfest 中声明

<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" />

2. 是想用怎样的方式来使用相机

可以有两种方式
2.1 简单的拍照 使用已经存在camera apps 
2.2 需要更多定制的功能,创建一个camera app

3. 存储方式

是只能在本应用程序里使用还是可以被其他程序使用。

二、相关类

android.hardware.camera2
包中包含控制设备相机的基本类
Camera
过时不用的相机控制类
SurfaceView
提供实时的相机预览
MediaRecorder 
用来记录video
Intent
使用
MediaStore.ACTION_IMAGE_CAPTURE
MediaStore.ACTION_VIDEO_CAPTURE
两个Intent类型来捕获图像和视频

三、Manifest声明

camera许可
<uses-permission android:name="android.permission.CAMERA" />
camera特征
<uses-feature android:name="android.hardware.camera" />
存储许可
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

音视频录制

<uses-permission android:name="android.permission.RECORD_AUDIO" />

位置许可

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

四、使用已经存在的camera apps

使用方式是用Intent,使用Intent能够使用最少的代码来获取图片
流程主要是
创建一个camera Intent,Intent的类型包括,MediaStore.ACTION_IMAGE_CAPTUREMediaStore.ACTION_VIDEO_CAPTURE启动一个camera Intent,使用startActivityForResult()方法来执行一个camera intent,在启动Intent后,camera应用界面能够显示在设备屏幕来供使用
接受Intent的结果,使用onActivityResult()方法来接受Intent的回调和数据。当用户结束拍照后,系统调用这一方法。
下列代码显示如何创建一个camera intent并执行
private static final int CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE = 100;
private Uri fileUri; @Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main); // create Intent to take a picture and return control to the calling application
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); fileUri = getOutputMediaFileUri(MEDIA_TYPE_IMAGE); // create a file to save the image
intent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri); // set the image file name // start the image capture Intent
startActivityForResult(intent, CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE);
}

接收camera intent的结果,主要是重载onActivityResult。

private static final int CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE = 100;
private static final int CAPTURE_VIDEO_ACTIVITY_REQUEST_CODE = 200; @Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE) {
if (resultCode == RESULT_OK) {
// Image captured and saved to fileUri specified in the Intent
Toast.makeText(this, "Image saved to:\n" +
data.getData(), Toast.LENGTH_LONG).show();
} else if (resultCode == RESULT_CANCELED) {
// User cancelled the image capture
} else {
// Image capture failed, advise user
}
}
}

!一但程序接受到一个成功的结果,那么应用程序就可以获取在指定路径下的图片。

五、创建一个Camera App

官方建议使用新的android.hardware.camera2,使用旧的Camera API会出现deprecated的警告。

一般创建一个定制Camera接口的步骤包括

1.检测和获取camera

/** Check if this device has a camera */
private boolean checkCameraHardware(Context context) {
if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)){
// this device has a camera
return true;
} else {
// no camera on this device
return false;
}
}
/** A safe way to get an instance of the Camera object. */
public static Camera getCameraInstance(){
Camera c = null;
try {
c = Camera.open(); // attempt to get a Camera instance
}
catch (Exception e){
// Camera is not available (in use or does not exist)
}
return c; // returns null if camera is unavailable
}

2.创建一个预览类

/** A basic Camera preview class */
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
private SurfaceHolder mHolder;
private Camera mCamera; public CameraPreview(Context context, Camera camera) {
super(context);
mCamera = camera; // Install a SurfaceHolder.Callback so we get notified when the
// underlying surface is created and destroyed.
mHolder = getHolder();
mHolder.addCallback(this);
// deprecated setting, but required on Android versions prior to 3.0
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
} public void surfaceCreated(SurfaceHolder holder) {
// The Surface has been created, now tell the camera where to draw the preview.
try {
mCamera.setPreviewDisplay(holder);
mCamera.startPreview();
} catch (IOException e) {
Log.d(TAG, "Error setting camera preview: " + e.getMessage());
}
} public void surfaceDestroyed(SurfaceHolder holder) {
// empty. Take care of releasing the Camera preview in your activity.
} public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
// If your preview can change or rotate, take care of those events here.
// Make sure to stop the preview before resizing or reformatting it. if (mHolder.getSurface() == null){
// preview surface does not exist
return;
} // stop preview before making changes
try {
mCamera.stopPreview();
} catch (Exception e){
// ignore: tried to stop a non-existent preview
} // set preview size and make any resize, rotate or
// reformatting changes here // start preview with new settings
try {
mCamera.setPreviewDisplay(mHolder);
mCamera.startPreview(); } catch (Exception e){
Log.d(TAG, "Error starting camera preview: " + e.getMessage());
}
}
}

3.创建一个预览的布局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<FrameLayout
android:id="@+id/camera_preview"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="1"
/> <Button
android:id="@+id/button_capture"
android:text="Capture"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
/>
</LinearLayout>
public class CameraActivity extends Activity {

    private Camera mCamera;
private CameraPreview mPreview; @Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main); // Create an instance of Camera
mCamera = getCameraInstance(); // Create our Preview view and set it as the content of our activity.
mPreview = new CameraPreview(this, mCamera);
FrameLayout preview = (FrameLayout) findViewById(R.id.camera_preview);
preview.addView(mPreview);
}
}

4.开始监听捕获事件

private PictureCallback mPicture = new PictureCallback() {

    @Override
public void onPictureTaken(byte[] data, Camera camera) { File pictureFile = getOutputMediaFile(MEDIA_TYPE_IMAGE);
if (pictureFile == null){
Log.d(TAG, "Error creating media file, check storage permissions: " +
e.getMessage());
return;
} try {
FileOutputStream fos = new FileOutputStream(pictureFile);
fos.write(data);
fos.close();
} catch (FileNotFoundException e) {
Log.d(TAG, "File not found: " + e.getMessage());
} catch (IOException e) {
Log.d(TAG, "Error accessing file: " + e.getMessage());
}
}
};

5.捕获并保存文件

// Add a listener to the Capture button
Button captureButton = (Button) findViewById(id.button_capture);
captureButton.setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View v) {
// get an image from the camera
mCamera.takePicture(null, null, mPicture);
}
}
);

保存图片到SD卡中

private PictureCallback mPicture = new PictureCallback() {

        /** Create a File for saving an image or video */

        @Override
public void onPictureTaken(byte[] data, Camera camera) { File pictureFile = getOutputMediaFile();
if (pictureFile == null) {
Log.d(TAG,"Error creating media file, check storage permissions: ");
return;
} try {
FileOutputStream fos = new FileOutputStream(pictureFile);
fos.write(data);
fos.close();
} catch (FileNotFoundException e) {
Log.d(TAG, "File not found: " + e.getMessage());
} catch (IOException e) {
Log.d(TAG, "Error accessing file: " + e.getMessage());
}
camera.startPreview(); } }; private File getOutputMediaFile() {
// To be safe, you should check that the SDCard is mounted
// using Environment.getExternalStorageState() before doing this. File mediaStorageDir = new File(
Environment
.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),
"MyCameraApp");
// This location works best if you want the created images to be shared
// between applications and persist after your app has been uninstalled. // Create the storage directory if it does not exist
if (!mediaStorageDir.exists()) {
if (!mediaStorageDir.mkdirs()) {
Log.d("MyCameraApp", "failed to create directory");
return null;
}
}
// Create a media file name
File mediaFile;
String timeStamp = String.format("%d.jpg", System.currentTimeMillis());
mediaFile = new File(mediaStorageDir.getPath() + File.separator
+ "IMG_" + timeStamp + ".jpg");
return mediaFile;
}

6.释放相机

public class CameraActivity extends Activity {
private Camera mCamera;
private SurfaceView mPreview;
private MediaRecorder mMediaRecorder; ... @Override
protected void onPause() {
super.onPause();
releaseMediaRecorder(); // if you are using MediaRecorder, release it first
releaseCamera(); // release the camera immediately on pause event
} private void releaseCamera(){
if (mCamera != null){
mCamera.release(); // release the camera for other applications
mCamera = null;
}
}
}

caution:

相机是一个共享资源,所以每次使用完毕后要记得调用Camera.release()来释放,否则后续想要获取相机的应用都会被关闭。

六、注意问题

6.1 拍完成照片后,停在拍照完成的界面,无法继续拍摄

在onPictureTaken的实现最后添加一个启动预览camera.startPreview();

private PictureCallback mPicture = new PictureCallback() {

        /** Create a File for saving an image or video */

        @Override
public void onPictureTaken(byte[] data, Camera camera) { File pictureFile = getOutputMediaFile();
if (pictureFile == null) {
Log.d(TAG,"Error creating media file, check storage permissions: ");
return;
} try {
FileOutputStream fos = new FileOutputStream(pictureFile);
fos.write(data);
fos.close();
} catch (FileNotFoundException e) {
Log.d(TAG, "File not found: " + e.getMessage());
} catch (IOException e) {
Log.d(TAG, "Error accessing file: " + e.getMessage());
}
camera.startPreview(); } };

代码:

https://github.com/dawnminghuang/android_camera

参考资料

http://developer.android.com/guide/topics/media/camera.html

Android学习十---Android Camera的更多相关文章

  1. [置顶] Android学习系列-Android中解析xml(7)

    Android学习系列-Android中解析xml(7) 一,概述 1,一个是DOM,它是生成一个树,有了树以后你搜索.查找都可以做. 2,另一种是基于流的,就是解析器从头到尾解析一遍xml文件.   ...

  2. android 学习十四 探索安全性和权限

    1.部署安全性:应用程序必须使用数字证书才能安装到设备上. 2.执行期间的安全性:    2.1 使用独立进程    2.2 使用固定唯一用户ID    2.3  申明性权限模型   3数字证书   ...

  3. Android学习十二---在android上实现图像匹配

    一.效果图及功能描述 效果图 点击ShowImg后 点击match,然后点击showmatch,可以不断点击showmatch. 主要功能描述:显示在SD卡上已经存在的图片test.jpg,根据图片在 ...

  4. android学习十四(android的接收短信)

    收发短信是每一个手机主要的操作,android手机当然也能够接收短信了. android系统提供了一系列的API,使得我们能够在自己的应用程序里接收和发送短信. 事实上接收短信主要是利用我们前面学过的 ...

  5. Android学习十二:自定义控件学习

    自定义控件: 1.定义控件的属性,atts.xml 2.代码实现自定义控件的控制 3.引用该控件 首先定义相关的属性 <?xml version="1.0" encoding ...

  6. android学习十二(android的Content Provider(内容提供器)的使用)

    文件存储和SharePreference存储以及数据存储一般为了安全,最好用于当前应用程序中訪问和存储数据.内容提供器(Content Provider)主要用于在不同的应用程序之间实现数据共享的功能 ...

  7. android学习十 ActionBar

    1.api level大于等于11 支持,或者使用兼容库,但兼容库的问题很多. 2.一个操作栏属于一个活动,并具有其生命周期 3.操作栏分3类:a.选项卡操作栏,b.列表操作栏,c.标准操作栏 4.获 ...

  8. Android学习——在Android中使用OpenCV的第一个程序

    刚開始学习Android,因为之前比較熟悉OpenCV,于是就想先在Android上执行OpenCV试试 =============================================== ...

  9. 【Android学习】android:layout_weight的用法实例

    对于android:layout_weight的用法,用下面的例子来说明: <LinearLayout xmlns:android="http://schemas.android.co ...

随机推荐

  1. CCNA2.0笔记_ACL

    要点: 1.按顺序执行,一旦某条语句匹配,后续语句不再处理. 2.默认ACL 结尾语句是deny any,所以你要记住的是在ACL 里至少要有1 条permit 语句. 3.记得创建了ACL 后要把它 ...

  2. CCNA2.0笔记_OSPF v2

    OSPF(开放最短路径优先)协议概述: - 链路状态路由协议 - 无类路由协议 - 要点:RouterID.区域ID - 触发更新 .以传播 LSA 代替路由表更新 - 快速响应变更(比距离矢量路由协 ...

  3. [转]C++11 标准新特性:Defaulted 和 Deleted 函数

    http://www.ibm.com/developerworks/cn/aix/library/1212_lufang_c11new/

  4. windows下安装vundle

    windows下安装vundle ## 前言 windows下安装vundle和linux下稍微有些不一样,虽然官网给出了 安装说明,但是有些问题的. E117: Unknown function: ...

  5. linux学习笔记6--命令mv

    mv命令是move的缩写,可以用来移动文件或者将文件改名(move (rename) files),是Linux系统下常用的命令,经常用来备份文件或者目录. mv命令用来对文件或目录重新命名,或者将文 ...

  6. 如何编写Makefile?

    //swap.c #include<stdio.h> int swap(int *x,int *y) {printf("a=%d b=%d\n",*x,*y); int ...

  7. 使用JSP实现用户登录

    本文讲述使用JSP实现用户登录,包括用户登录.注册和退出功能等. 1.系统用例图 2.页面流程图 3.数据库设计 本例使用oracle数据库 创建用户表 包括id,username,password和 ...

  8. 2017-2018 ACM-ICPC, NEERC, Northern Subregional Contest D Dividing Marbles

    题目大意: 给出一个$N(N <= 2^{22}$),$N$的二进制表示中1的个数不超过4.  一开始有一个集合$S = {N}$, 每次操作可以选择$n\in S \ (n > 1)$, ...

  9. 【vijos】1763 Wormhole(贪心)

    https://vijos.org/p/1764 首先第一个虫洞一定是建在1号点. 证明如下: 假设一个虫洞在a,一个在b,a<b,那么走到k点的最短距离为 min{|x1-xk|, |x1-x ...

  10. Openstack(Kilo)安装系列之glance(六)

    安装配置 Before you install and configure the Image service, you must create a database, service credent ...