2. CameraX基础预览

任务说明

本案例目标:使用CameraX实现相机预览,并对比Camera2的差异。你需要完成一个可运行的Android应用模块,该模块通过CameraX的Preview用例将相机画面实时显示在PreviewView上,同时提供Camera2与CameraX在API设计、生命周期处理、线程模型三个维度上的代码级差异对比。

实现方案

采用CameraX 1.3.x版本,使用ProcessCameraProvider绑定Preview用例。核心流程为:初始化PreviewView → 获取ProcessCameraProvider → 创建Preview并设置SurfaceProvider → 选择后置相机 → 绑定生命周期。Camera2对比部分以注释形式嵌入关键代码位置,展示两者在会话建立与预览回调上的差异。

代码实现

// CameraXPreviewFragment.kt
class CameraXPreviewFragment : Fragment() {
    private var previewView: PreviewView? = null
    private var cameraProvider: ProcessCameraProvider? = null
    private var camera: Camera? = null

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        previewView = inflater.inflate(R.layout.fragment_camera_x, container, false) as PreviewView
        return previewView
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        startCamera()
    }

    private fun startCamera() {
        val cameraProviderFuture = ProcessCameraProvider.getInstance(requireContext())
        cameraProviderFuture.addListener({
            try {
                cameraProvider = cameraProviderFuture.get()
                bindPreview()
            } catch (e: Exception) {
                Log.e("CameraXDemo", "Camera provider init failed", e)
            }
        }, ContextCompat.getMainExecutor(requireContext()))
    }

    private fun bindPreview() {
        val provider = cameraProvider ?: return
        val preview = Preview.Builder()
            .setTargetResolution(Size(1280, 720))
            .build()

        // Camera2差异点1:CameraX使用SurfaceProvider自动管理Surface生命周期,
        // 而Camera2需要手动创建CameraCaptureSession并管理SurfaceView/SurfaceTexture。
        preview.setSurfaceProvider(previewView?.surfaceProvider)

        val selector = CameraSelector.Builder()
            .requireLensFacing(CameraSelector.LENS_FACING_BACK)
            .build()

        try {
            // Camera2差异点2:CameraX通过bindToLifecycle自动处理相机打开/关闭与配置,
            // 而Camera2需在onResume中openCamera,在onPause中closeCamera。
            camera = provider.bindToLifecycle(
                viewLifecycleOwner,
                selector,
                preview
            )
        } catch (e: Exception) {
            Log.e("CameraXDemo", "Bind failed", e)
        }
    }

    override fun onDestroyView() {
        super.onDestroyView()
        // Camera2差异点3:CameraX在Fragment销毁时自动解绑,
        // 而Camera2需在onDestroy中手动释放CameraDevice与CaptureSession。
        cameraProvider?.unbindAll()
        previewView = null
    }
}
<!-- fragment_camera_x.xml -->
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <androidx.camera.view.PreviewView
        android:id="@+id/preview_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</FrameLayout>
// build.gradle (Module级) 关键依赖
dependencies {
    implementation "androidx.camera:camera-core:1.3.4"
    implementation "androidx.camera:camera-camera2:1.3.4"
    implementation "androidx.camera:camera-lifecycle:1.3.4"
    implementation "androidx.camera:camera-view:1.3.4"
    implementation "androidx.core:core-ktx:1.12.0"
    implementation "androidx.appcompat:appcompat:1.6.1"
    implementation "androidx.fragment:fragment-ktx:1.6.2"
}

Camera2对比说明

上述代码中三处注释已标注Camera2对应实现方式。核心差异总结如下:

  • API抽象层级:CameraX的Preview用例封装了相机设备、会话、流配置等细节,而Camera2要求开发者直接操作CameraDevice、CameraCaptureSession和CaptureRequest。
  • 生命周期绑定:CameraX通过bindToLifecycle自动响应ON_START/ON_STOP事件,Camera2需在Activity/Fragment生命周期方法中手动调用openCamera和closeCamera。
  • 预览Surface管理:CameraX的SurfaceProvider自动处理Surface的创建、尺寸匹配与销毁,Camera2需自行监听SurfaceHolder.Callback或SurfaceTexture.OnFrameAvailableListener。

运行与验证

  1. 在Android Studio中创建新项目,将上述Fragment添加到MainActivity中,并确保AndroidManifest.xml已声明CAMERA权限。
  2. 在Android 6.0+设备上运行时,需在MainActivity中动态请求相机权限。
  3. 运行应用后,观察PreviewView是否实时显示后置相机画面。
  4. 旋转设备屏幕,确认预览画面方向正确且无黑屏闪烁,验证生命周期绑定生效。
  5. 在Logcat中过滤CameraXDemo标签,确认无异常堆栈输出。

判定标准:预览画面流畅显示、旋转屏幕后自动恢复预览、无内存泄漏(反复进出页面后内存稳定)即为通过。