在本課程中,我們將討論如何直接使用 架構 API
注意:本頁面所述是指已淘汰的相機類別。建議使用 CameraX,或者,在特定情況使用 Camera2。CameraX 和 Camera2 均支援 Android 5.0 (API 級別 21) 以上版本。
比起要求圖片或影片,直接控制裝置相機的程式碼要多上許多 從現有相機應用程式中移除不過,如果您想要建構專用的相機應用程式 或完全整合到您的應用程式 UI 中,本課程將說明如何進行這些操作。
請參閱下列相關資源:
開啟相機物件
如要取得 Camera
物件的執行個體,
直接控制相機的程序如同 Android 本身「相機」應用程式,
如要存取相機,建議的做法是在另一個執行緒上開啟 Camera
還有從 onCreate()
啟動的 Pod這種做法
因為可能需要一些時間才能完成,而且可能會使 UI 執行緒停滯。在基本的導入方式中
開啟相機可延遲給 onResume()
方法,以便重複使用程式碼,並保持
控制簡單
呼叫 Camera.open()
會擲回
因為其他應用程式正在使用攝影機,所以我們會將其包裝
在 try
區塊中。
Kotlin
private fun safeCameraOpen(id: Int): Boolean { return try { releaseCameraAndPreview() mCamera = Camera.open(id) true } catch (e: Exception) { Log.e(getString(R.string.app_name), "failed to open Camera") e.printStackTrace() false } } private fun releaseCameraAndPreview() { preview?.setCamera(null) mCamera?.also { camera -> camera.release() mCamera = null } }
Java
private boolean safeCameraOpen(int id) { boolean qOpened = false; try { releaseCameraAndPreview(); camera = Camera.open(id); qOpened = (camera != null); } catch (Exception e) { Log.e(getString(R.string.app_name), "failed to open Camera"); e.printStackTrace(); } return qOpened; } private void releaseCameraAndPreview() { preview.setCamera(null); if (camera != null) { camera.release(); camera = null; } }
自 API 級別 9 開始,相機架構可支援多部相機。如果您使用
舊版 API 並呼叫 open()
,而沒有
引數時,你就會得到第一個後置鏡頭。
建立相機預覽
拍照時,使用者通常需要看到拍攝主體的預覽畫面,才會點選
快門。方法是使用 SurfaceView
繪製
相機感應器正在偵測。
預覽類別
如要開始顯示預覽畫面,必須具備預覽類別。
預覽需要實作 android.view.SurfaceHolder.Callback
介面,用來傳遞圖片
將相機硬體資料傳送至應用程式
Kotlin
class Preview( context: Context, val surfaceView: SurfaceView = SurfaceView(context) ) : ViewGroup(context), SurfaceHolder.Callback { var mHolder: SurfaceHolder = surfaceView.holder.apply { addCallback(this@Preview) setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS) } ... }
Java
class Preview extends ViewGroup implements SurfaceHolder.Callback { SurfaceView surfaceView; SurfaceHolder holder; Preview(Context context) { super(context); surfaceView = new SurfaceView(context); addView(surfaceView); // Install a SurfaceHolder.Callback so we get notified when the // underlying surface is created and destroyed. holder = surfaceView.getHolder(); holder.addCallback(this); holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); } ... }
預覽類別必須在直播期間傳遞至 Camera
物件
即可開始預覽圖片,如下一節所示。
設定並開始預覽
您必須在特定物件中建立相機執行個體及其相關預覽
將相機物件放在最前面在下方程式碼片段中,
會封裝相機的初始化程序,讓模型呼叫 Camera.startPreview()
setCamera()
方法,每當使用者變更
相機上另外也必須在預覽類別 surfaceChanged()
回呼方法中重新啟動預覽。
Kotlin
fun setCamera(camera: Camera?) { if (mCamera == camera) { return } stopPreviewAndFreeCamera() mCamera = camera mCamera?.apply { mSupportedPreviewSizes = parameters.supportedPreviewSizes requestLayout() try { setPreviewDisplay(holder) } catch (e: IOException) { e.printStackTrace() } // Important: Call startPreview() to start updating the preview // surface. Preview must be started before you can take a picture. startPreview() } }
Java
public void setCamera(Camera camera) { if (mCamera == camera) { return; } stopPreviewAndFreeCamera(); mCamera = camera; if (mCamera != null) { List<Size> localSizes = mCamera.getParameters().getSupportedPreviewSizes(); supportedPreviewSizes = localSizes; requestLayout(); try { mCamera.setPreviewDisplay(holder); } 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(); } }
修改相機設定
相機設定會改變相機從變焦拍照的方式 曝光補償等級這個範例只會變更預覽大小。 查看相機應用程式的原始碼
Kotlin
override fun surfaceChanged(holder: SurfaceHolder, format: Int, w: Int, h: Int) { mCamera?.apply { // Now that the size is known, set up the camera parameters and begin // the preview. parameters?.also { params -> params.setPreviewSize(previewSize.width, previewSize.height) requestLayout() parameters = params } // Important: Call startPreview() to start updating the preview surface. // Preview must be started before you can take a picture. startPreview() } }
Java
@Override 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(previewSize.width, previewSize.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 標頭中。setCameraDisplayOrientation()
方法可讓您
但不影響圖片錄製方式。不過,在 Android 之前
至 API 級別 14,則必須先停止預覽,才能變更方向並重新啟動。
拍攝相片
使用「Camera.takePicture()
」
方法,開始預覽後拍照。您可以建立 Camera.PictureCallback
和 Camera.ShutterCallback
物件,並將其傳遞至 Camera.takePicture()
。
如要持續擷取圖片,可以建立實作 onPreviewFrame()
的 Camera.PreviewCallback
。適用對象
也可以只擷取選定的預覽畫面
呼叫 takePicture()
。
重新開始預覽
使用者拍照後,必須重新啟動預覽。 可以拍攝另一張相片此範例是透過超載而重新啟動 快門按鈕
Kotlin
fun onClick(v: View) { previewState = if (previewState == K_STATE_FROZEN) { camera?.startPreview() K_STATE_PREVIEW } else { camera?.takePicture(null, rawCallback, null) K_STATE_BUSY } shutterBtnConfig() }
Java
@Override public void onClick(View v) { switch(previewState) { case K_STATE_FROZEN: camera.startPreview(); previewState = K_STATE_PREVIEW; break; default: camera.takePicture( null, rawCallback, null); previewState = K_STATE_BUSY; } // switch shutterBtnConfig(); }
停止預覽並釋出相機
應用程式完成相機拍攝後,可開始進行清除。於
您必須釋出 Camera
物件,否則,
包括您應用程式的新執行個體
何時應停止預覽並釋出相機?嗯,擁有
預覽表面被破壞時,最好能
預覽並釋出相機,如 Preview
類別中的這些方法所示。
Kotlin
override fun surfaceDestroyed(holder: SurfaceHolder) { // Surface will be destroyed when we return, so stop the preview. // Call stopPreview() to stop updating the preview surface. mCamera?.stopPreview() } /** * When this function returns, mCamera will be null. */ private fun stopPreviewAndFreeCamera() { mCamera?.apply { // Call stopPreview() to stop updating the preview surface. 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()). release() mCamera = null } }
Java
@Override 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()
方法的一部分,因此初始化相機一律從停止
預覽。