2. 预览流程实现:使用 PreviewView、绑定生命周期、实现实时预览回调
2.1 预览架构原理
CameraX 的预览流程围绕三个核心组件展开:PreviewView(显示视图)、Preview(用例配置)和 LifecycleOwner(生命周期绑定)。PreviewView 封装了 SurfaceView / TextureView,通过 SurfaceProvider 机制与 CameraX 的 Preview 用例建立连接。CameraX 监听 LifecycleOwner 的状态,自动在 ON_START 时开启预览、ON_STOP 时停止预览,无需手动管理相机生命周期。
实时预览回调是指开发者能够在每一帧预览数据送达 Surface 后获得通知,从而进行图像处理(如人脸检测、滤镜叠加)。CameraX 1.2+ 推荐使用 ImageAnalysis 用例实现帧级回调;亦可基于 Preview 的 OnPreviewOutputUpdateListener(已废弃)或自定义 SurfaceProvider 的 onSurfaceRequested 中额外创建ImageReader。
实时预览与显示的区别:Preview 仅负责将相机数据渲染到 Surface,不提供每帧回调。需要图像分析时,必须额外绑定 ImageAnalysis 用例到同一生命周期。
2.2 实现流程
- 添加 CameraX 依赖:在模块级
build.gradle中引入 CameraX 库。 - 布局中声明 PreviewView:在 XML 中放置
androidx.camera.view.PreviewView。 - 获取 LifecycleOwner:Fragment / Activity 本身即为 LifecycleOwner,确保
lifecycle可用。 - 创建 ProcessCameraProvider:通过
ProcessCameraProvider.getInstance(context)获取单例实例,并在ListenableFuture回调中配置。 - 构建 Preview 用例:使用
Preview.Builder设置分辨率、旋转等参数,调用build()生成对象。 - 设置 SurfaceProvider:从 PreviewView 获取
getSurfaceProvider()并传递给 Preview 的setSurfaceProvider()。 - 绑定生命周期:调用
cameraProvider.bindToLifecycle(lifecycleOwner, cameraSelector, preview, imageAnalysis)。 - 添加实时帧回调(可选):创建
ImageAnalysis用例,设置分析器,并绑定到同一生命周期。
2.3 关键代码实现
// build.gradle (模块级)
dependencies {
def camerax_version = "1.3.1"
implementation "androidx.camera:camera-core:${camerax_version}"
implementation "androidx.camera:camera-camera2:${camerax_version}"
implementation "androidx.camera:camera-lifecycle:${camerax_version}"
implementation "androidx.camera:camera-view:${camerax_version}"
}
// PreviewActivity.kt
class PreviewActivity : AppCompatActivity() {
private lateinit var previewView: PreviewView
private lateinit var cameraProviderFuture: ListenableFuture<ProcessCameraProvider>
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_preview)
previewView = findViewById(R.id.previewView)
cameraProviderFuture = ProcessCameraProvider.getInstance(this)
cameraProviderFuture.addListener({
val cameraProvider = cameraProviderFuture.get()
bindPreview(cameraProvider)
}, ContextCompat.getMainExecutor(this))
}
private fun bindPreview(cameraProvider: ProcessCameraProvider) {
val preview = Preview.Builder().build()
val surfaceProvider = previewView.surfaceProvider
preview.setSurfaceProvider(surfaceProvider)
// 可选:实时预览回调(ImageAnalysis)
val imageAnalysis = ImageAnalysis.Builder()
.setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
.build()
imageAnalysis.setAnalyzer(ContextCompat.getMainExecutor(this)) { imageProxy ->
// 处理每一帧(imageProxy)
imageProxy.close()
}
val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA
cameraProvider.unbindAll()
cameraProvider.bindToLifecycle(
this, cameraSelector, preview, imageAnalysis
)
}
}
2.4 API 参考
| API | 说明 |
|---|---|
ProcessCameraProvider.getInstance(context) | 获取 CameraX 单例,管理相机生命周期和用例绑定 |
Preview.Builder.build() | 创建预览用例,可配置分辨率、目标旋转等 |
PreviewView.getSurfaceProvider() | 返回预览视图提供的 SurfaceProvider,用于连接 Preview |
Preview.setSurfaceProvider(SurfaceProvider) | 将 Preview 输出定向到指定 Surface |
cameraProvider.bindToLifecycle(lifecycleOwner, cameraSelector, vararg useCases) | 绑定生命周期,自动管理用例的开启/停止 |
ImageAnalysis.Analyzer | 分析器接口,在每一帧上执行回调 |
2.5 调试与验证
- 预览黑屏:检查
CAMERA权限是否在运行时申请,且 AndroidManifest.xml 中声明<uses-permission android:name="android.permission.CAMERA" />。 - 生命周期日志:在
bindToLifecycle前添加Log.d(TAG, "binding preview"),并在onStart/onStop中确认日志。 - SurfaceProvider 是否已设置:若
preview.setSurfaceProvider(null)则无画面。确保在绑定前调用。 - 分辨率适配:使用
Preview.Builder().setTargetResolution(Size(1920,1080))设置目标分辨率,避免默认分辨率不合预期。
常见错误:
cameraProvider.unbindAll()未调用导致重复绑定抛出异常。- 在 Fragment 中未使用
viewLifecycleOwner而是使用this,导致离开 Fragment 后预览未释放。 - 未设置
ImageAnalysis的背压策略,导致内存堆积。
2.6 性能与稳定性优化
- 预览尺寸选择:使用
setTargetResolution配合Preview.Builder,避免过大的 Surface 导致 GPU 过载。推荐 1280×720 平衡清晰度与性能。 - 帧率控制:不进行实时帧回调时,不要创建
ImageAnalysis用例;若需要,设置STRATEGY_KEEP_ONLY_LATEST避免队列积压。 - 焦点模式:通过
CameraX的CameraControl或Preview.Builder的扩展设置连续自动对焦。 - 生命周期解绑:在
onDestroy或 Fragment 视图销毁时,确保cameraProvider.unbindAll()已被调用(bindToLifecycle内部已处理,但显式调用可提前释放资源)。
2.7 预览流程示意图
2.8 部署注意事项
- Android 最低版本要求:CameraX 1.3 要求 minSdkVersion ≥ 21。
- 在 Fragment 中使用时,生命周期应绑定到
viewLifecycleOwner,而非 Fragment 自身,避免在视图重建时回调混乱。 - 在 Android 10+ 设备上,建议测试不同相机缩放比下的预览清晰度,必要时调用
CameraControl.setZoomRatio()。 - 若应用需要在后台保持预览(如画中画),需额外处理
CameraX暂停恢复逻辑,通常不推荐。
2.9 常见问题排查
| 现象 | 可能原因 | 解决措施 |
|---|---|---|
| 预览黑屏 | 权限未授予;SurfaceProvider 未设置;生命周期未绑定 | 申请权限;检查 preview.setSurfaceProvider();确认 bindToLifecycle 调用 |
| 预览闪烁/卡顿 | 分辨率过高;CPU 负载过高 | 降低目标分辨率;关闭 ImageAnalysis;减少 UI 动画 |
| 实时回调不触发 | ImageAnalysis 未绑定;分析器阻塞 | 确认 setAnalyzer 调用;确保回调中及时 close() 释放 |
| App 崩溃: “Camera is closing” | 在停止生命周期后仍然调用相机 | 使用 LifecycleObserver 或 LiveData 避免异步回调 |