Android官方开发文档Training系列课程中文版:调用相机之控制相机
原文地址:http://android.xsoftlab.net/training/camera/cameradirect.html
在這節(jié)課,我們會(huì)討論如何使用Android框架API來(lái)直接控制相機(jī)硬件。
直接控制設(shè)備的相機(jī)拍照或者攝像的代碼遠(yuǎn)比通過(guò)其他相機(jī)應(yīng)用來(lái)完成要多得多。然而,如果你想構(gòu)建一個(gè)專業(yè)的相機(jī)應(yīng)用或者在APP的UI中完全集成相機(jī)的話,這節(jié)課展示了如何去做。
開(kāi)啟相機(jī)對(duì)象
直接控制相機(jī)的第一步就是獲得Camera對(duì)象的實(shí)例。和Android自身的相機(jī)應(yīng)用相同,推薦訪問(wèn)相機(jī)的方式就是在獨(dú)立的線程打開(kāi)Camera,這種方式是應(yīng)對(duì)阻塞UI線程的一個(gè)好的解決方法。在更加基礎(chǔ)化的實(shí)現(xiàn)當(dāng)中,開(kāi)啟相機(jī)這一步操作可以推遲到onResume()方法中執(zhí)行,這樣可以促使代碼重用并且保持簡(jiǎn)單的控制流。
如果相機(jī)已經(jīng)正在被其它應(yīng)用所使用,那么調(diào)用Camera.open()方法會(huì)拋出一個(gè)異常,所以我們需要使用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), "failed to open Camera");e.printStackTrace();}return qOpened; } private void releaseCameraAndPreview() {mPreview.setCamera(null);if (mCamera != null) {mCamera.release();mCamera = null;} }從API 9開(kāi)始,相機(jī)框架支持多個(gè)相機(jī)。如果你使用的是過(guò)去的API,然后調(diào)用了沒(méi)有參數(shù)的open()方法,那么你會(huì)獲得后置面板的相機(jī)。
創(chuàng)建相機(jī)預(yù)覽
拍照通常需要可以使用戶能看到目標(biāo)的預(yù)覽圖。你可以使用SurfaceView來(lái)繪制相機(jī)傳感器捕獲到的圖像。
預(yù)覽類
為了可以顯示預(yù)覽,你需要預(yù)覽類。預(yù)覽需要一個(gè)android.view.SurfaceHolder.Callback接口的實(shí)現(xiàn),它被用來(lái)從相機(jī)硬件給應(yīng)用傳遞圖像數(shù)據(jù)。
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);} ... }在開(kāi)始預(yù)覽之前,必須將預(yù)覽對(duì)象傳遞給Camera對(duì)象,就像下面部分展示的那樣。
設(shè)置并開(kāi)始預(yù)覽
相機(jī)實(shí)例的創(chuàng)建于相關(guān)預(yù)覽對(duì)象創(chuàng)建必須是以指定順序進(jìn)行的,從相機(jī)對(duì)象開(kāi)始。在下面的代碼中,實(shí)例化相機(jī)對(duì)象的過(guò)程被封裝起來(lái)了,所以Camera.startPreview()是可以通過(guò)setCamera()調(diào)用的,每當(dāng)用戶做了什么事情使相機(jī)發(fā)生了改變。預(yù)覽也必須在預(yù)覽類的surfaceChanged()回調(diào)方法重新啟動(dòng)。
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();} }修改相機(jī)設(shè)置
相機(jī)設(shè)置可以改變相機(jī)拍照的方式,從縮放等級(jí)到曝光補(bǔ)償?shù)鹊取O旅娴氖纠皇歉牧祟A(yù)覽的大小;請(qǐng)查看相機(jī)應(yīng)用的源代碼獲取更多可能。
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(); }設(shè)置預(yù)覽方向
大多數(shù)的相機(jī)應(yīng)用將展示鎖定在了水平方向,因?yàn)檫@是相機(jī)傳感器的自然方向。這個(gè)設(shè)置并不能阻止你在垂直方向上拍攝,因?yàn)橄鄼C(jī)的方向會(huì)被記錄到EXIF的頭部。setCameraDisplayOrientation()方法允許你改變?nèi)绾握故绢A(yù)覽,而不受圖像記錄方向的影響。然而,在API14之前,在改變方向之前必須停止預(yù)覽,然后在重新啟動(dòng)它。
拍照
一旦預(yù)覽啟動(dòng)后,可以使用Camera.takePicture()方法來(lái)拍一張照片。你可以創(chuàng)建Camera.PictureCallback對(duì)象和Camera.ShutterCallback對(duì)象然后將它們傳遞給Camera.takePicture()方法。
重啟預(yù)覽
在拍了一張照片之后,你必須在用戶拍另一張照片之前重新啟動(dòng)預(yù)覽。在這個(gè)例子中,通過(guò)重寫快門按鈕來(lái)完成重啟。
@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;} // switchshutterBtnConfig(); }停止預(yù)覽并且釋放相機(jī)
一旦你的程序不再需要使用相機(jī),這時(shí)就需要執(zhí)行清理工作。尤其是你需要釋放相機(jī)對(duì)象,否則會(huì)使其它程序面臨崩潰的風(fēng)險(xiǎn),包括你自己程序中新的實(shí)例。
何時(shí)應(yīng)該停止預(yù)覽并釋放相機(jī)呢?好吧,當(dāng)預(yù)覽界面被銷毀的時(shí)候便是停止預(yù)覽并釋放相機(jī)的最佳時(shí)機(jī),就像下面Preview類中顯示的那樣:
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// during onPause() and re-open() it during onResume()).mCamera.release();mCamera = null;} }在上面的課程中,這段程序也是setCamera()方法的一部分,所以實(shí)例化一個(gè)相機(jī)總是從停止這段預(yù)覽開(kāi)始的。
總結(jié)
以上是生活随笔為你收集整理的Android官方开发文档Training系列课程中文版:调用相机之控制相机的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 【JavaWeb】JDBC的基本操作和事
- 下一篇: Android官方开发文档Trainin