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 的三层架构:应用层、库层、底层 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 优先绑定,执行器要区分主次。后面的章节里,我们会拿着这份配置一一解析预览启动的每个环节,看哪里能砍掉无谓的等待时间。