近期這段時間我一直在開發自己定義相機。谷歌了些網上的demo。發現有非常多各種各樣的問題。終於還是從API的camera類開始學習,進行改進。
以下對之前的實現進行一些總結。
官方camera API:
http://developer.android.com/guide/topics/media/camera.html
中文翻譯:
http://www.cnblogs.com/over140/archive/2011/11/16/2251344.html
自己定義相機大致實現流程:
預覽Camera這一塊。有三個類能夠實現:Surfaceview、GLSurfaceView、TextureView。Android4.0自帶Camera應用採用SurfaceView預覽,Android4.2採用GLSurfaceView來預覽。Android4.4採用TextureView。
這三者的差別和聯系請看這篇文章 Android 5.0(Lollipop)中的SurfaceTexture,TextureView, SurfaceView和GLSurfaceView
我這里總結採用Surfaceview預覽camera的自己定義相機開發。
1. Manifest聲明
確保在清單文件增加Camera權限。存儲權限等等。
2. 創建預覽類
使用SurfaceView控件實現攝像頭實時預覽畫面。
SurfaceView是View的子類。所以它擁有View的一切方法和屬性。
同一時候多出的Surface專門用來繪制的類。
SurfaceView有以下三個特點:
A. 具有獨立的畫圖表面。
B. 須要在宿主窗體上挖一個洞來顯示自己。
C. 它的UI繪制能夠在獨立的線程中進行。這樣就能夠進行復雜的UI繪制。而且不會影響應用程序的主線程響應用戶輸入。
來自 Android視圖SurfaceView的實現原理分析
創建一個繼承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中,連同其他用戶界面控件一起(拍照button。攝像頭切換)。實現拍照或攝像功能。這里注意要採用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;
}
}