編輯:Android開發實例
本節課主要講述怎樣通過調用系統的framework APIs來控制設備的攝像頭操作。
相比調用系統內置的其他相機應用來拍照和攝像,自己編寫代碼來直接控制相機操作需要更多的工作,然而,如果您要設計一款專業的拍照應用,或者相機功能與您的UI界面進行深度整合,那麼您可以從本節課找到所需的知識。
自己編寫代碼控制相機的第一步就是獲得一個Camera 實例對象,與Android系統內置的其他相機應用類似,推薦的方法是在onCreate()方法中啟動一個新的線程來開啟相機,因為這個過程可能比較耗時,新啟一個線程來處理可以有效避免UI主線程的停頓,另一種方式是將開啟相機的過程推遲到 onResume() 方法中,這樣便於代碼的重用和簡化流程控制。
如果此時有其他應用正在使用相機,那麼當您的程序調用方法Camera.open() 的時候會出現異常,需要進行捕獲( try block)。
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), "failed to open Camera"); e.printStackTrace(); } return qOpened; } private void releaseCameraAndPreview() { mPreview.setCamera(null); if (mCamera != null) { mCamera.release(); mCamera = null; } }
從 API level 9 開始,camera framework 支持用戶程序控制多個相機,如果您在調用方法open() 的時候沒有傳遞任何參數,那麼系統會默認啟動Androd設備的第一個後置攝像頭。
按下快門鍵拍照以前,用戶希望看到當前相機的預覽畫面,要實現此功能,那麼您可以使用SurfaceView,通過獲取實時的相機捕獲的數據並展示到界面上。
自定義預覽界面類型(Preview Class)
要創建一個預覽畫面,需要自定義一個畫面預覽類型(preview class)。您需要實現 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); // Install a SurfaceHolder.Callback so we get notified when the // underlying surface is created and destroyed. mHolder = mSurfaceView.getHolder(); mHolder.addCallback(this); mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); } ... }
在開啟相機的預覽操作前,您必須首先將自定義的預覽界面實例對象處傳遞給Camera 實例對象,稍後會有介紹。
設置和開啟預覽(Set and Start the Preview)
創建Camera實例和創建與其綁定的預覽界面實例必須按照一個特定的順序,且創建Camera實例必須是第一步。下面的實例代碼中,將開啟相機的預覽操作封裝在一個函數中,這樣可以保證不論用戶什麼時候只要調用過 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(); } /* Important: Call startPreview() to start updating the preview surface. Preview must be started before you can take a picture. */ mCamera.startPreview(); } }
在控制相機拍照的過程中可以修改相機的配置參數,比如放大倍率,曝光補償等等,示例代碼展示了修改相機的預覽畫面大小,如果想了解更多的配置參數請參閱Camera APP的源代碼。
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { // Now that the size is known, set up the camera parameters and begin // the preview. Camera.Parameters parameters = mCamera.getParameters(); parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height); requestLayout(); mCamera.setParameters(parameters); /* Important: Call startPreview() to start updating the preview surface. Preview must be started before you can take a picture. */ mCamera.startPreview(); }
多數相機應用在啟動預覽的時候,默認選定在橫屏模式,因為這是相機傳感器最自然的方向,但是,這些設定並不影響您拍攝豎屏模式的照片,當前設備的方向會記錄在照片的EXIF header中。方法setCameraDisplayOrientation() 可以用來改變預覽畫面的方向而不影響最終照片的拍攝方向。需要注意的是在API level 14之前,您需要首先停止預覽畫面,切換橫豎屏模式,再重新啟動預覽畫面。
在預覽的過程中,調用方法 Camera.takePicture() 來拍攝照片,可以創建Camera.PictureCallback 和 Camera.ShutterCallback 實例對象作為參數傳遞給方法 Camera.takePicture() 中。想要實現連續拍照,需要實現接口Camera.PreviewCallback 中的onPreviewFrame()函數,在實現代碼中,您可以捕獲當前選定的預覽幀,或者設定一個延遲時間來調用拍照函數 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; } // switch shutterBtnConfig(); }
一旦您的應用使用完了相機,那麼應該及時釋放資源。特別地,需要釋放Camera 實例對象,否則可能會破壞其他應用程序的執行,包括您自己應用的重新啟動。
那麼哪個地方是最合適停止預覽與釋放Camera資源的呢?預覽畫面銷毀的回調函數中是個不錯的選擇。需要參照前面實現的自定義預覽類型( Preview class)。
public void surfaceDestroyed(SurfaceHolder holder) { // Surface will be destroyed when we return, so stop the preview. if (mCamera != null) { /* Call stopPreview() to stop updating the preview surface. */ mCamera.stopPreview(); } } /** * When this function returns, mCamera will be null. */ private void stopPreviewAndFreeCamera() { if (mCamera != null) { /* Call stopPreview() to stop updating the preview surface. */ mCamera.stopPreview(); /* Important: Call release() to release the camera for use by other applications. Applications should release the camera immediately in onPause() (and re-open() it in onResume()). */ mCamera.release(); mCamera = null; } }
本節課的開始部分,setCamera() 方法中,在初始化camera 實例之前總是首先停止預覽。
參考文摘:
http://developer.android.com/training/camera/cameradirect.html
原文:http://blog.zhourunsheng.com/2012/01/android-%e7%9b%b8%e7%89%87%e7%ae%a1%e7%90%86%e4%b8%93%e9%a2%98%e4%b9%8b%e7%9b%b8%e6%9c%ba%e6%93%8d%e4%bd%9c/ | 潤物無聲
關於 android 常用布局,利用 XML 文件實現已經有很多的實例了。但如何利用代碼實現呢?當然利用代碼實現沒有太大的必要,也是不提倡的,但我覺得利用代碼實現
ToggleButton的狀態只能是選中和未選中,並且需要為不同的狀態設置不同的顯示文本。 以下案例為ToggleButton的用法 目錄結構 main.xml
Android應用程序可以在許多不同地區的許多設備上運行。為了使應用程序更具交互性,應用程序應該處理以適合應用程序將要使用的語言環境方面的文字,數字,文件等。在本章中,我
本文主要講解利用android中Matrix控制圖形的旋轉縮放移動,具體參見一下代碼:代碼如下:/** * 使用矩陣控制圖片移動、縮放、旋轉 &nbs