CameraX 核心概念与生命周期绑定

CameraX 是 Jetpack 家族中专为相机功能设计的库,它通过 用例(UseCase) 抽象了相机常见的操作场景。本章将深入理解 Preview、ImageCapture、ImageAnalysis 三个核心用例,并掌握如何将它们绑定到 LifecycleOwner,从而实现自动化生命周期管理。

3.1 三大核心用例概览

用例 职责 典型输出 生命周期行为
Preview 提供实时取景画面,通常与 PreviewView 配合 Surface / Texture Resume 时自动打开相机,Pause 时释放
ImageCapture 单张照片拍摄,支持闪关灯、对焦、EXIF 文件 / Bitmap / MediaStore 拍完自动释放,状态无关
ImageAnalysis 连续帧图像分析,用于二维码扫描、人脸检测等 ImageProxy 可配置背压策略(最新帧或所有帧)

三个用例可以同时绑定到同一个 LifecycleOwner,CameraX 会按照以下顺序依次激活:Preview → ImageCapture → ImageAnalysis。绑定后您无需手动管理相机启动/停止,LifecycleOwner 的 resume/pause 事件会自动传递给 CameraX。

3.2 生命周期绑定机制

CameraX 的核心思想是 声明式绑定:您不需要自己调用 camera.open() / camera.close(),而是将用例声明给 ProcessCameraProvider,并让它与 LifecycleOwner 关联。示意图如下:

CameraX 生命周期绑定流程 LifecycleOwner (Activity / Fragment) ON_RESUME ProcessCameraProvider (单例全局) 绑定用例 Preview ImageCapture bindToLifecycle ImageAnalysis 可选绑定 Camera 实例 Lifecycle 事件自动 控制相机开关

3.3 实现流程

  1. 添加依赖 – 在 build.gradle 引入 CameraX 库,注意版本对齐。
  2. 声明权限 – CAMERA 权限,Android 10+ 可选录音权限。
  3. 获取 ProcessCameraProvider – 通过 ProcessCameraProvider.getInstance(context) 异步获取。
  4. 创建用例 – 分别构造 Preview、ImageCapture、ImageAnalysis 并配置参数。
  5. 绑定到 LifecycleOwner – 调用 provider.bindToLifecycle(lifecycleOwner, cameraSelector, useCases)。
  6. 获取 Camera 控制权 – 绑定成功后返回 Camera 对象,可调整 zoom、torch 等。

3.4 代码实战:Jetpack Compose 中绑定

在 Compose 中通过 AndroidView 嵌入 PreviewView,并在 DisposableEffect 中完成绑定。核心代码片段:

@Composable
fun CameraPreview(
    lifecycleOwner: LifecycleOwner = LocalLifecycleOwner.current,
    modifier: Modifier = Modifier
) {
    val context = LocalContext.current
    var camera by remember { mutableStateOf<Camera?>(null) }

    AndroidView(
        factory = { ctx ->
            val previewView = PreviewView(ctx)
            val providerFuture = ProcessCameraProvider.getInstance(ctx)
            providerFuture.addListener({
                val provider = providerFuture.get()
                val preview = Preview.Builder().build().also {
                    it.setSurfaceProvider(previewView.surfaceProvider)
                }
                val imageCapture = ImageCapture.Builder()
                    .setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY)
                    .build()
                val imageAnalysis = ImageAnalysis.Builder()
                    .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
                    .build()
                // 选择后置摄像头
                val selector = CameraSelector.DEFAULT_BACK_CAMERA
                try {
                    // 解绑现有用例
                    provider.unbindAll()
                    camera = provider.bindToLifecycle(
                        lifecycleOwner, selector, preview, imageCapture, imageAnalysis
                    )
                } catch (e: Exception) {
                    Log.e("CameraX", "绑定失败", e)
                }
            }, ContextCompat.getMainExecutor(ctx))
            previewView
        },
        modifier = modifier
    )
}

关键点:

  • unbindAll() 确保 View 复用前解绑旧用例,避免泄漏。
  • ImageAnalysis 的 STRATEGY_KEEP_ONLY_LATEST 在帧处理慢时会自动丢弃旧的,避免队列堆积。
  • 所有创建和绑定操作必须在主线程执行,使用 ContextCompat.getMainExecutor。

3.5 调试与部署注意事项

检查项 说明
AndroidManifest 权限 <uses-permission android:name="android.permission.CAMERA"/>,若需录音加上 RECORD_AUDIO
相机硬件需求 在 AndroidManifest 声明 <uses-feature android:name="android.hardware.camera" android:required="false"/> 避免 Google Play 过滤
设备兼容性测试 CameraX 1.0+ 覆盖 Android 5.0 以上 99% 设备,但部分低端机可能不支持同时绑定三个用例
ProGuard 规则 如果开启混淆,需保留 CameraX 相关类:-keep class androidx.camera.** { *; }

调试技巧:使用 adb shell dumpsys media.camera 查看相机状态;CameraX 1.2+ 提供了 CameraXConfig 设置日志级别。

3.6 常见错误与解决方案

  • CameraInfoUnavailableException – 多发生在模拟器或没有摄像头的设备。解决方案:检测 PackageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA),并在 UI 提示用户。
  • 绑定后预览未显示 – 常见原因:PreviewView 未设置 surfaceProvider,或 bindToLifecycle 传入的 lifecycleOwner 生命周期已销毁。确保在 DisposableEffect 中绑定,并在离开时调用 provider.unbindAll()。
  • ImageCapture 无法拍照 – 检查是否给 ImageCapture 传递了 OutputFileOptions,并且文件存储目录有写入权限。
  • ImageAnalysis 收到空帧 – 通常是分辨率不兼容,使用 setTargetResolution(Size(1280, 720)) 限制。

3.7 性能与稳定性优化

重要:同时绑定多个用例会增加 GPU 和内存负载。以下建议可提升稳定性:

  1. 选择合适的分辨率 – Preview 和 ImageAnalysis 使用相同尺寸可减少缩放开销。推荐 720p 或 1080p。
  2. ImageAnalysis 背压策略 – 始终使用 STRATEGY_KEEP_ONLY_LATEST,避免分析回调耗尽线程池。
  3. 异步处理分析结果 – 在 ImageAnalysis.Analyzer 中不要阻塞主线程,使用 Executors.newSingleThreadExecutor() 处理帧。
  4. 及时释放资源 – 如果不再需要 ImageAnalysis,调用 provider.unbind(analysisUseCase) 释放帧缓冲区。
  5. 复用 ProcessCameraProvider – 该对象全局单例,避免重复初始化。

3.8 总结

本章掌握了 CameraX 三大用例的职责与生命周期绑定原理。核心要点:

  • 声明式绑定 使代码简洁,免去手动管理相机开关。
  • 用例组合 可以自由搭配,但受设备硬件的约束。
  • ImageAnalysis 的背压策略 是防止 ANR 的关键。
  • 使用 AndroidView 在 Compose 中集成,并注意 DisposableEffect 的生命周期匹配。

下一步将在第4章中实战预览画面显示与相机切换。