控制相机
打开相机
获得Camera对象是直接控制相机的第一步。对于Android自带相机应用,控制相机推荐的方法是在onCreate()中开启另外的线程打开相机,以防止阻塞UI线程。在更基本的实现中,打开相机可以在onResume()中执行,以复用代码及保持简单的控制流。
如果相机已经被其它应用占用,调用Camera.open()会抛出一个异常,所以加在try代码块中。
private boolean safeCameraOpen(int id){
boolean qOpened = false;
try{
releaseCameraAndPreview();
mCamera = Camera.open(id);
qOpened = (mCamera != null);
}catch(Exception e){
Log.e(getString(R.string.app_name),"打开相机失败");
e.printStackTrace();
}
return qOpened;
}
private void releaseCameraAndPreview(){
mPreview.setCamera(null);
if(mCamera != null){
mCamera.release();
mCamera = null
}
}
API为9及以上,相机框架支持多个相机,如果使用之前版本的API调用open()不带参数,将会返回第一个后置摄相头。
创建相机预览
拍照之前一般需要看到事物的预览效果,可以使用SurfaceView画出相机传感器正在接收的预览。
Preview类
在显示预览之前,需要preview类。需要实现android.view.SurfaceHolder.Callback接口,用来传输从相机到应用的图像数据。
class Preview extends ViewGroup implements SurfaceHolder.Callback{
SurfaceView mSurfaceView;
SurfaceHolder mHolder;
Preview(Context context){
super(context);
mSurfaceView = new SurfaceView(context);
addView(mSurfaceView);
//设置SurfaceHolder.Callback,当surface被创建和销毁时可以获得通知
mHolder = mSurfaceView.getHolder();
mHolder.addCallback(this);
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
...
}
预览类必须在直播的图像预览开始前传递给相机对像。
设置和开始预览
一个相机对象和它相关联的预览必须以特定的顺序创建。在下面的代码片段中,相机初始化的过程被封装,当用户改变相机时,setCamera()方法会调用Camera.startPreview()方法。预览必须在预览类surfaceChanged()方法中重启。
public void setCamera(Camera camera){
if(mCamera == camera){return;}
stopPreviewAndFreeCamera();
mCamera = camera;
if(mCamera != null){
List<Size> localSizes = mCamera.getParameters().getSupportedPreviewSizes();
mSupportedPreviewSizes = localSizes;
requestLayout();
try{
mCamera.setPreviewDisplay(mHolder);
}catch(IOException e){
e.printStackTrace();
}
//注意:调用startPreview()开始更新预览surface。预览必须在拍照之前开启。
mCamera.startPreview();
}
}
修改相机设置
相机设置改变相机拍照的方式,从缩放级别到曝光补偿。这个例子只改变预览尺寸。
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h){
//大小已经知道,设置相机参数和开始预览
Camera.Parameters parameters = mCamera.getParameters();
parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
requestLayout();
mCamera.setParameters(parameters);
//注意:调用startPreview()开始更新预览surface。预览必须在拍照之前开始。
mCamera.startPreview();
}
设置预览方向
大多数相机应用将显示锁定为横向模式,因为这是相机传感器的自然定位。这个设置并不能阴止你使用竖直模式,因为设备的方向是在EXIF头文件中记录的。setCameraDisplayOrientation()方法能改变预览显示模式并且不影响图片的记录。然而,在API级别为14之前的系统中,必须在改变方向前停止预览,然后重新打开。
拍照
一旦预览启动,就可以通过Camera.takePicture()方法拍照。可以创建Camera.pictureCallback和Camera.ShutterCallback对象,并传递给Camera.takePicture().
如果想要连续的获取图片,可以创建实现了OnPreviewFrame()的Camera.PreviewCallback。对于两者之间的,可以捕获选定的预览帧,或者设定一个延迟的动作来调用takePicture().
重启预览
拍照后,在拍下一张照片前必须重启预览。在本例中,重启是在重载快门按钮中完成的。
@Override
public void onClick(View v){
switch(mPreviewState){
case K_STATE_FROZEN:
mCamera.startPreview();
mPreviewState = K_STATE_PREVIEW;
break;
default:
mCamera.takePicture(null, rawCallback, null);
mPreviewState = K_STATE_BUSY;
}
shutterBtnConfig();
}
停止预览和释放相机
一旦应用使用相机结束,就该清理了。一般来说,必须释放Camera对象,否则可能会导致其它应用崩溃,包括自己应用的新对象。
当预览surface销毁就可以停止预览和释放相机了,就像之前在Preview类中显示的。
public void surfaceDestroyed(){
//当返回时Surface会被销毁,所以要停止预览
if(mCamera != null){
//调用stopPreview()来停止更新预览surface
mCamera.stopPreview();
}
}
private void stopPreviewAndFreeCamera(){
if(mCamera != null){
mCamera.stopPreview();
//注意:调用release()来释放相机以供其它应用使用。应用应该在onPause()中立即释放相机,并且在onResume()中重新打开
mCamera.release();
mCamera = null;
}
}
在文单前面,这个过程也是setCamera()方法的一部分,所以初始化相面就是以停止预览开始。