Android知识要点整理----控制相机
Posted znapast
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android知识要点整理----控制相机相关的知识,希望对你有一定的参考价值。
除了调用第三方APP进行拍照外,我们还可以自己使用系统API来控制相机设备进行拍照。这个相对来说比较复杂。下面只讲比较关键的步骤。
1.声明权限
控制照相机我们需要声明使用照相设备的权限。
<uses-feature android:name="android.hardware.camera" android:required="true"/>
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera.autofocus" android:required="false" />
我们声明feature的required
属性为true,这样没有相机设备的手机就没法安装APP。若设置为false,我们就需要在代码中检测是否具有相机设备,若有的话则开启拍照功能,否则需要禁用该功能。判断方法如下:
if(getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA))
photoBtn.setOnClickListener(this);
else
photoBtn.setVisibility(View.GONE);
if(getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_AUTOFOCUS))
//开启自动聚焦模块
2.打开相机设备
打开相机设备就是获得相机的一个实例,它是IO操作,所以可能比较耗时。为了避免ANR,我们需要在onCreate
或onResume
方法中另开一个线程去执行IO操作。相机设备可能会被其他APP占用,这时调用Camera.open()
方法会抛出异常。安全地打开相机设备的代码如下:
@Override
protected void onResume()
super.onResume();
//另开一个线程
new Thread(new Runnable()
@Override
public void run()
if(safeCameraOpen(0))
mHandler.post(new Runnable()
@Override
public void run()
if(mPreview != null)
//设置给预览视图,mPreview 为SurfaceView的子类
mPreview.setCamera(mCamera);
);
).start();
/**
*打开指定的相机设备,id为相机序号,<=相机设备数量-1
**/
private boolean safeCameraOpen(int id)
boolean qOpened = false;
try
//确保之前的实例已经被正确关闭并释放
releaseCameraAndPreview();
mCamera = Camera.open(id);
qOpened = (mCamera != null);
if(mCamera != null)
mCamera.setDisplayOrientation(90);
catch (Exception e)
Log.e(getString(R.string.app_name), "failed to open Camera");
e.printStackTrace();
return qOpened;
private void releaseCameraAndPreview()
if(mPreview != null)
mPreview.setCamera(null);
if (mCamera != null)
mCamera.release();
mCamera = null;
上面的代码在onResume
方法中安全的打开设备。同样重要的是,我们要在onPause
方法中确保相机设备被正确的关闭和释放,这样就不会阻碍其他APP使用相机设备。
@Override
protected void onPause()
releaseCameraAndPreview();
super.onPause();
3.关联相机和预览视图
要在拍照前预览效果,我们要构造预览视图,这个视图通常是继承自SurfaceView
的自定义视图。SurfaceView
能够非UI线程中绘制界面,因为预览效果需要频繁更新界面,使用它可以避免阻塞UI线程。下面是自定义的CameraPreview
的完整代码:
package com.github.znacloud.multimediademo.view;
import android.content.Context;
import android.hardware.Camera;
import android.util.AttributeSet;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import java.io.IOException;
import java.util.List;
/**
* Created by Stephan on 2016/1/15.
*/
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback
private SurfaceHolder mHolder;
private Camera mCamera;
private List<Camera.Size> mSupportedPreviewSizes;
public CameraPreview(Context context)
super(context);
inits(context);
public CameraPreview(Context context, AttributeSet attrs)
super(context, attrs);
inits(context);
public CameraPreview(Context context, AttributeSet attrs, int defStyleAttr)
super(context, attrs, defStyleAttr);
inits(context);
private void inits(Context pContext)
mHolder = getHolder();
mHolder.addCallback(this);
@Override
public void surfaceCreated(SurfaceHolder holder)
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height)
if(mCamera == null) return;
Camera.Parameters parameters = mCamera.getParameters();
//根据视图的尺寸设置预览图的尺寸
parameters.setPreviewSize(width, height);
mCamera.setParameters(parameters);
requestLayout();
// 必须调用startPreview里面更新视图
mCamera.startPreview();
@Override
public void surfaceDestroyed(SurfaceHolder holder)
if (mCamera != null)
// 视图销毁时停止预览
mCamera.stopPreview();
public void setCamera(Camera camera)
if (mCamera == camera) return;
//设置新的相机实例之前确保旧的相机实例被正确的释放和关闭
stopPreviewAndFreeCamera();
mCamera = camera;
if (mCamera != null)
List<Camera.Size> localSizes = mCamera.getParameters().getSupportedPreviewSizes();
//TODO:根据设备支持的预览尺寸设置视图尺寸
try
//关联到SurfaceView
mCamera.setPreviewDisplay(mHolder);
catch (IOException e)
e.printStackTrace();
//每次更新了相机实例后都要调用此方法开启预览功能
mCamera.startPreview();
private void stopPreviewAndFreeCamera()
if (mCamera != null)
// 停止预览
mCamera.stopPreview();
// 释放设备,这样其他APP就可以继续使用相机设备
mCamera.release();
mCamera = null;
接下来就是在成功打开相机设备后将相机实例关联到预览视图。
if(mPreview != null)
mPreview.setCamera(mCamera);
try
mCamera.setPreviewDisplay(mHolder);
catch (IOException e)
e.printStackTrace();
4.拍摄照片
上面的工作做完了之后我们就可以正式拍摄照片了。使用Camera.takePicture()
方法可以执行拍摄照片的动作,该方法可以传入多个回调函数。看API文档:
我们现在只做最简单的拍照,实现代码如下:
private static final int K_STATE_FROZEN = 0;
private static final int K_STATE_PREVIEW = 1;
private static final int K_STATE_BUSY = 2;
......
mCaptureBtn = (Button)findViewById(R.id.btn_shutter);
mCaptureBtn.setOnClickListener(new View.OnClickListener()
@Override
public void onClick(View v)
if(mPreviewState == K_STATE_FROZEN)
mCamera.startPreview();
mPreviewState = K_STATE_PREVIEW;
else if(mPreviewState == K_STATE_PREVIEW)
mCamera.takePicture(null,rawCallBack,null);
mPreviewState = K_STATE_BUSY;
);
由于在拍照完成后相机会自动进入冻结状态,我们需要根据状态来重新启动预览状态。上面的代码使用了拍照按钮来响应两种不同的操作,若当前为预览状态,点击按钮将立即拍照,此后相机进入冻结状态,再次点击按钮就只是恢复预览状态,不执行拍照。拍照时我们只传了一个回调函数rawCallBack
,该回调类定义如下:
private Camera.PictureCallback rawCallBack = new Camera.PictureCallback()
@Override
public void onPictureTaken(byte[] data, Camera camera)
mPreviewState = K_STATE_FROZEN;
//TODO:data中保存的是照片的原始数据,我们可以对其进行处理,保存为照片或者其他事情
;
到此为止,我们已经控制相机拍摄一张完整的照片了。当然,想要界面更加友好,更易使用,我们需要添加一些细节,比如添加快门声,添加聚焦效果,添加人脸检测功能等等。这些功能,系统都有提供API,我们只需要实现响应的界面反馈出来就行了,这里就不详细介绍了。
以上是关于Android知识要点整理----控制相机的主要内容,如果未能解决你的问题,请参考以下文章
Android知识要点整理----Bitmap图片处理和展示
android知识要点整理(14)----Volley(HTTP请求框架)