最近这段时间我一直在开发自定义相机,谷歌了些网上的demo,发现有很多各种各样的问题。最终还是从API的camera类开始学习,进行改进。下面对之前的实现进行一些总结。

自定义相机大致实现流程:

android开发选择系统相机拍照 android 相机开发_实时预览


预览Camera这一块,有三个类可以实现:Surfaceview、GLSurfaceView、TextureView。Android4.0自带Camera应用采用SurfaceView预览,Android4.2采用GLSurfaceView来预览。Android4.4采用TextureView。

我这里总结采用Surfaceview预览camera的自定义相机开发。

1. Manifest声明
确保在清单文件加入Camera权限,存储权限等等。
2. 创建预览类
使用SurfaceView控件实现摄像头实时预览画面。
SurfaceView是View的子类,所以它拥有View的一切方法和属性。同时多出的Surface专门用来绘制的类。
SurfaceView有以下三个特点:

A. 具有独立的绘图表面;

    B. 需要在宿主窗口上挖一个洞来显示自己;

    C. 它的UI绘制可以在独立的线程中进行,这样就可以进行复杂的UI绘制,并且不会影响应用程序的主线程响应用户输入。


创建一个继承surfaceView和实现SurfaceHolder.Callback的类,SurfaceHolder.CallBack用来监听Surface的变化,实现三个方法:
(1)surfaceCreated(SurfaceHolder holder):在该类创建的时候调用。进行打开camera操作,如何实现看下一步。
(2)surfaceChanged(SurfaceHolder holder, int format, int width,int height):在surface改变时候调用,这里实现图形的绘制。进行开始预览操作,如何实现看下一步。
(3)surfaceDestroyed(SurfaceHolder holder):在surface销毁时候调用,这里一般对资源进行释放。进行释放摄像头等操作。
3. 封装CameraInterface类
采用单例模式创建CameraInterface类,里面操作Camera的检测、打开、预览、拍照、关闭以及保存图片的回调。

CheckCamera(Context mContext)
doOpenCamera(Context mContext,int cameraId)
doStartPreview(SurfaceHolder holder, float previewRate)
doStopCamera()
...

这样在上一步里,我们只需获得CameraInterface实例后直接调用方法。这种方式使Camera的逻辑和界面的UI耦合度降低。同时也保证了程序的扩展性和可重用性。
4. 创建自定义布局

第二步的摄像预览类必须被放入一个activity的layout中,连同其它用户界面控件一起(拍照按钮,摄像头切换),实现拍照或摄像功能。这里注意要采用FrameLayout容纳摄像预览类,可以把附加的图片信息或控件叠加到实时预览画面上。比如要实现中间亮四周暗的实时预览界面,则我们需要在这里自定义view。
5. 创建相机Activity
这里就是控件注册,监听控件点击事件等。
同样的takePicture拍照,切换摄像头后重新创建相机实例都封装在CameraInterface类中。
6. 拍照以及保存图片
拍照会在上一步控件点击事件发生,触发mCamera.takePicture(mShutterCallback, mRawCallback, mJpegPictureCallback);
这里需要实现拍照的快门声音、拍照保存照片的回调方法。同样都在单例类CameraInterface中实现。
同时要注意需求,如果拍照后继续实时预览,则要再次触发doStartPreview。如果是跳转到预览Activity则通过Intent进行跳转。
7. 释放摄像头

/**
     * 停止预览,释放Camera
     */
    public void doStopCamera(){
        if(null != mCamera)
        {
            mCamera.setPreviewCallback(null);
            mCamera.stopPreview(); 
            isPreviewing = false; 
            mPreviwRate = -1f;
            mCamera.release();
            mCamera = null;     
        }
    }