3、CameraX库引入与常见配置归纳总结

好,从这一章开始,咱们真正动手干活。聊了这么多理论,你得先把 CameraX 请进项目里才行。我这些年折腾过不少相机方案,CameraX 算是少有的让我觉得「嗯,这个设计挺聪明」的库——它把 Camera2 那套复杂的状态机包装成了几个好懂的 UseCase,大大降低了预览、拍照、分析这些场景的门槛。

3.1 为什么是 CameraX?

别急着写代码,先搞清楚一个问题:为啥官方大力推 CameraX,而不是继续用 Camera2?

  • 生命周期感知:你不需要手动管理相机打开、关闭和 Activity/Fragment 绑定了。我记得第一次用 Camera2 时,花了两天处理各种 onPause/onResume 的竞态,后来切到 CameraX,一行 lifecycle 绑定就解决了。
  • 设备兼容性:CameraX 内部有一个「兼容性库」,会自动检测不同厂商设备上的 Camera2 实现差异,帮你做绕行。我曾在某款国产机上遇到过预览画面拉伸的问题,换成 CameraX 后,它自己选了最合适的输出尺寸。
  • 用例组合灵活:想同时做预览和拍照?直接用 Preview 和 ImageCapture 两个 UseCase 叠加就行,底层会自动帮你分配 Session。

一句话总结:CameraX 是 Google 官方提供的 Jetpack 组件,专门用于简化 Android 相机开发。只要你 targetSdk 高于 21,放心用。

3.2 引入依赖

打开你的 build.gradle(模块级),在 dependencies 里加上下面这几行。注意版本号我建议统一用 1.3.0 及以上,因为后续章节我们会用到 CameraX Extensions 的某些特性。

dependencies {
    // CameraX core
    def camerax_version = "1.3.0"
    implementation "androidx.camera:camera-core:${camerax_version}"
    implementation "androidx.camera:camera-camera2:${camerax_version}"
    implementation "androidx.camera:camera-lifecycle:${camerax_version}"

    // 如果你想用 CameraX 的 View(PreviewView),加上这个
    implementation "androidx.camera:camera-view:${camerax_version}"

    // 如果需要图片分析(ImageAnalysis),加上这行
    implementation "androidx.camera:camera-extensions:${camerax_version}"
}

嗯,简单解释一下:camera-core 是核心,camera-camera2 是底层实现,camera-lifecycle 是用来绑定生命周期的。三个缺一不可。我见过有人只加了 core 就开写,结果运行时疯狂报 NoSuchMethodError……记住,三个都要加。

小提示:如果你用 androidx.camera:camera-extensions,请确认你的设备厂商提供了扩展实现,比如美颜、HDR。不是所有手机都支持,但加了不会出问题。

3.3 常见配置与最佳实践

引入完依赖只是第一步。CameraX 虽然号称「零配置可用」,但真要跑出高性能预览,有几个配置点必须抓住。我按使用频率排个序,你按这个顺序检查项目就行。

配置项 推荐值 说明
Preview 分辨率 Size(1920, 1080) 用于预览的 Surface,不是越大越好。1080p 足够清晰且性能均衡。
ImageAnalysis 分析器 CODEC_ANALYZER 或 CPU_BUFFER 如果只是做图像格式转换,选 CPU_BUFFER 更快;需要解码则用 CODEC_ANALYZER。
CameraSelector DEFAULT_BACK_CAMERA 或 LENS_FACING_BACK 明确指定后摄或前摄,别用模糊的 ANY,避免在某些手机上弹出选择对话框。
执行器(Executor) ContextCompat.getMainExecutor(context) 大部分回调在主线程,但 ImageAnalysis 的 analyzer 建议用 Executors.newSingleThreadExecutor() 避免卡界面。

举个例子,基本配置的代码长这样:

// 获取一个 ProcessCameraProvider
val cameraProviderFuture = ProcessCameraProvider.getInstance(context)
cameraProviderFuture.addListener({
    val cameraProvider = cameraProviderFuture.get()

    // 创建 Preview 用例
    val preview = Preview.Builder()
        .setTargetResolution(Size(1920, 1080))
        .build()

    // 创建 ImageAnalysis 用例(可选)
    val imageAnalysis = ImageAnalysis.Builder()
        .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
        .build()
    imageAnalysis.setAnalyzer(executor, { imageProxy ->
        // 处理你的图像数据
        imageProxy.close()
    })

    // 选择后摄
    val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA

    // 绑定生命周期
    cameraProvider.bindToLifecycle(
        lifecycleOwner,
        cameraSelector,
        preview,
        imageAnalysis
    )
}, ContextCompat.getMainExecutor(context))

避坑指南:我曾经在 bindToLifecycle 时忘了传 lifecycleOwner,结果相机一直无法打开,报了个「Session 被拒绝」的异常。检查一下 Activity 是否实现了 LifecycleOwner——如果是 AppCompatActivity 默认就有,片段需要确保生命周期不早于 onStart。

3.4 优化预览启动的额外配置

好了,基础配置搞定了,但我们的目标是「预览启动耗时优化」。那就要在配置阶段就埋好伏笔:

  • 延迟初始化非必要 UseCase:如果你只是在启动时预览,别急着把 ImageCapture 和 ImageAnalysis 都绑上去。先只绑 preview,等用户点击拍照按钮时再加 UseCase。这样 CameraSession 的创建会快一截。
  • 使用 Preview.SurfaceProvider 的 surface 回调:别在 UI 线程上创建 Surface。可以把 previewView 的 surfaceProvider 设置到 Preview 对象,这样 CameraX 自己会按需创建 Surface。
  • 关闭不必要的扩展:有些手机厂商的 CameraX 扩展会在启动时加载额外滤镜,会拖慢 100~200ms。如果你不需要美颜、HDR,直接用 Preview.Builder().setImplementationMode(Preview.ImplementationMode.COMPATIBLE) 强制走兼容模式,反而更快。

我亲身经历过:某次在低端机上,默认扩展模式让预览启动用了 1.2 秒,换成 COMPATIBLE 后直接降到 800ms。你想想看,这 400ms 对于用户感知来说有多重要。

3.5 整个流程你心里要有数

为了让你对 CameraX 的模块关系有个直观印象,我画了张图。这张图会伴随我们后续所有章节——每一次优化都离不开这六个模块的协作。

CameraX 核心模块与启动流程 应用层 LifecycleOwner PreviewView Activity / Fragment CameraX 库层 CameraProvider UseCase(Preview / ImageCapture) CameraXConfig 底层 Camera2 CameraManager / CameraDevice 关键配置 分辨率 / 帧率 CameraSelector Executor 优化关注点 UseCase 组合策略 SurfaceProvider 时机 扩展模式选择 启动耗时 从 bind → onSurfaceReady

这张图里,左边是 CameraX 的三层架构:应用层、库层、底层 Camera2。右边是我们后续要反复优化的三个配置模块。每次你调整某一项,启动耗时就会跟着变。我在做优化时,脑子里就会浮现这张图,然后问自己:「我现在动的是哪一层?影响的是哪个用例?」

3.6 关于版本更迭的提醒

CameraX 目前还在快速迭代,我写这段时最新稳定版是 1.3.0。但等你看到课程时,可能已经有 1.4.x 了。我建议你打开 https://developer.android.com/jetpack/androidx/releases/camera 确认最新版。如果版本变了,改动通常很小,大概率只是接口签名微调,核心思路不变。

特别警告:不要在 onCreate 里直接 bindToLifecycle!我以前在小米手机上遇到一个 bug:onCreate 时 Activity 还没完成 measure,PreviewView 的尺寸为 0,导致 CameraX 内部创建 Surface 失败。正确的姿势是在 onResume 或通过 view.post 确保 View 已 Layout 完毕后再绑定。

好,到这里 CameraX 的引入和基础配置就说完了。记住今天的重点:三个依赖一个都不能少,preview 优先绑定,执行器要区分主次。后面的章节里,我们会拿着这份配置一一解析预览启动的每个环节,看哪里能砍掉无谓的等待时间。