在 使用Intent调用Android系统自身的相机功能 中,演示了如何使用 intent 调用内置的相机进行拍照。本文我们将演示如何使用 Camera2 API 完成拍照任务。对于想要定制相机的开发人员来说,理解 Camera2 API 是必须要掌握的。
声明权限 使用相机并保存拍摄的相片,需要在应用的 AndroidManifest.xml 加入权限声明相机和存储的权限:
1 2 3 <uses-permission android:name ="android.permission.CAMERA" /> <uses-permission android:name ="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-feature android:name ="android.hardware.camera2.full" />
构造界面 构造一个包含一个 TextureView 和两个 Button 的界面, TextrueView 用来显示相机镜头所拍摄到的画面。
activity_main.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 <?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android ="http://schemas.android.com/apk/res/android" xmlns:app ="http://schemas.android.com/apk/res-auto" xmlns:tools ="http://schemas.android.com/tools" android:layout_width ="match_parent" android:layout_height ="match_parent" tools:context =".MainActivity" > <TextureView android:id ="@+id/tuwPhoto" android:layout_width ="0dp" android:layout_height ="0dp" app:layout_constraintBottom_toTopOf ="@+id/linearLayout" app:layout_constraintEnd_toEndOf ="parent" app:layout_constraintHorizontal_bias ="0.0" app:layout_constraintStart_toStartOf ="parent" app:layout_constraintTop_toTopOf ="parent" /> <LinearLayout android:id ="@+id/linearLayout" android:layout_width ="match_parent" android:layout_height ="wrap_content" android:orientation ="horizontal" app:layout_constraintBottom_toBottomOf ="parent" app:layout_constraintEnd_toEndOf ="parent" app:layout_constraintStart_toStartOf ="parent" > <Button android:id ="@+id/btnOpenCamera" android:layout_width ="wrap_content" android:layout_height ="wrap_content" android:layout_weight ="1" android:text ="Open Camera" /> <Button android:id ="@+id/btnTakePhoto" android:layout_width ="wrap_content" android:layout_height ="wrap_content" android:layout_weight ="1" android:text ="Take Photo" /> </LinearLayout > </androidx.constraintlayout.widget.ConstraintLayout >
构建一个TextrueView 的监听器 使用 SurfaceTextureListener 监听器来监听(响应)TexttrueView 状态变化的情况
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 TextureView.SurfaceTextureListener textureListener = new TextureView.SurfaceTextureListener() { @Override public void onSurfaceTextureAvailable (SurfaceTexture surface, int width, int height) { } @Override public void onSurfaceTextureSizeChanged (SurfaceTexture surface, int width, int height) { } @Override public boolean onSurfaceTextureDestroyed (SurfaceTexture surface) { return false ; } @Override public void onSurfaceTextureUpdated (SurfaceTexture surface) { } };
构建一个相机状态的回调接口类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 private final CameraDevice.StateCallback stateCallback = new CameraDevice.StateCallback() { @Override public void onOpened (CameraDevice camera) { cameraDevice = camera; createCameraPreview(); } @Override public void onDisconnected (CameraDevice camera) { cameraDevice.close(); } @Override public void onError (CameraDevice camera, int error) { cameraDevice.close(); cameraDevice = null ; } };
创建一个相机会话回调接口 1 2 3 4 5 6 7 8 final CameraCaptureSession.CaptureCallback captureCallbackListener = new CameraCaptureSession.CaptureCallback() { @Override public void onCaptureCompleted (CameraCaptureSession session, CaptureRequest request, TotalCaptureResult result) { super .onCaptureCompleted(session, request, result); Toast.makeText(MainActivity.this , "Saved:" + file, Toast.LENGTH_LONG).show(); createCameraPreview(); } };
在按钮事件中打开相机 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 private void openCamera () { CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE); Log.e(TAG, "Open camera..." ); try { cameraId = manager.getCameraIdList()[0 ]; CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId); StreamConfigurationMap map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); assert map != null ; imageDimension = map.getOutputSizes(SurfaceTexture.class)[0]; this .checkPermission(); manager.openCamera(cameraId, stateCallback, null ); } catch (CameraAccessException e) { e.printStackTrace(); } Log.e(TAG, "openCamera completed." ); }