--- tags: Android --- # 使用CameraX preview 相機畫面 CameraX是Jetpack支援的套件,根據google的描述,該套件是對camera2進行的封裝,它提供了更加簡單的API介面,可於Android 5.0以上等級的系統上執行。 CameraX可與Lifecycle綁定在一起,所以開發人員就不需要去處理何時應該要釋放相機的問題,都交給Lifecycle去處理。 ## 權限 需要的CAMERA權限,如果你要儲存相片,還需要WRITE_EXTERNAL_STORAGE的權限,因為這裡我們只要預覽而已所以只需要以下權限 ``` =xml <uses-permission android:name="android.permission.CAMERA" /> ``` ## 環境需求 CameraX 需要的最低需求: 1. Android API level 21 2. Android Architecture Components 1.1.1 ## Dependencies ``` =groovy def camerax_version = "1.0.0-beta07" // CameraX core library using camera2 implementation implementation "androidx.camera:camera-camera2:$camerax_version" // CameraX Lifecycle Library implementation "androidx.camera:camera-lifecycle:$camerax_version" // CameraX View class implementation "androidx.camera:camera-view:1.0.0-alpha14 ``` ## layout設計 在layout中新增previewView。 ``` =xml <androidx.camera.view.PreviewView android:id="@+id/camerax_previewView" android:layout_width="match_parent" android:layout_height="match_parent"/> ``` ## 開始實作 先取得PerviewView ``` =java private PreviewView mPreviewView; ... private void findView(){ mPreviewView = findViewById(R.id.camerax_previewView); ... } ``` 第二步取得ProcessCameraProvider,用來綁定生命週期跟設定使用前後相機等。 ``` =java //異步執行ProcessCameraProvider.getInstance ListenableFuture<ProcessCameraProvider> cameraProviderFuture = ProcessCameraProvider.getInstance(this); ``` 透過上面一段的程式碼,可以看到是利用Future對取得ProcessCameraProvider進行非同步的處理.我們可以透過下方ProcessCameraProvider.getInstance的source code窺探裡面的作法: ``` =java @NonNull public static ListenableFuture<ProcessCameraProvider> getInstance( @NonNull Context context) { Preconditions.checkNotNull(context); return Futures.transform(CameraX.getOrCreateInstance(context), cameraX -> { sAppInstance.setCameraX(cameraX); return sAppInstance; }, CameraXExecutors.directExecutor()); } ``` 所以接下來我們必須要給cameraProviderFuture增加一的監聽,用來監聽ProcessCameraProvider.getInstance(),一旦等到這個非同步的function完成後,可以接著往下執行. ``` =java cameraProviderFuture.addListener(new Runnable() { @Override public void run() { //Preview Preview preview = new Preview.Builder().build(); preview.setSurfaceProvider(mPreviewView.createSurfaceProvider()); } }, ContextCompat.getMainExecutor(this)); ``` 上面第一個參數則是當監聽的function完成後應該要執行的事情,透過Runnable執行.第二個參數則是指定用什麼執行緒執行.接著我們先在Runnable裡面建立好Perview並設定好SurfaceProvider. 接著我們開始對ProcessCameraProvider進行生命週期的綁定以及將剛剛設定好的Preview一起傳進去. ``` =java try { //取得異步執行ProcessCameraProvider.getInstance的執行結果 ProcessCameraProvider cameraProvider = cameraProviderFuture.get(); cameraProvider.unbindAll(); //綁定生命週期並且使用前相機,綁定的生命週期也可以自訂 cameraProvider.bindToLifecycle(MainActivity.this, CameraSelector.DEFAULT_FRONT_CAMERA,preview); } catch (ExecutionException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } ``` 整個function完成後程式碼如下: ``` =java /** * 啟動相機預覽 */ private void startCamera(){ //異步執行ProcessCameraProvider.getInstance ListenableFuture<ProcessCameraProvider> cameraProviderFuture = ProcessCameraProvider.getInstance(this); //新增監聽,待ProcessCameraProvider.getInstance執行完成後run以下步驟。 cameraProviderFuture.addListener(new Runnable() { @Override public void run() { //Preview Preview preview = new Preview.Builder().build(); preview.setSurfaceProvider(mPreviewView.createSurfaceProvider()); try { //取得異步執行ProcessCameraProvider.getInstance的執行結果 ProcessCameraProvider cameraProvider = cameraProviderFuture.get(); cameraProvider.unbindAll(); //綁定生命週期並且使用前相機,綁定的生命週期也可以自訂 cameraProvider.bindToLifecycle(MainActivity.this, CameraSelector.DEFAULT_FRONT_CAMERA,preview); } catch (ExecutionException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } } }, ContextCompat.getMainExecutor(this)); } ``` 以上就是CameraX實現preview的簡單介紹. ## 參考資料 https://developer.android.com/training/camerax https://codelabs.developers.google.com/codelabs/camerax-getting-started#3