第四章 创建CameraX预览用例

4.1 原理概述

CameraX 预览(Preview)用例是连接相机硬件与屏幕显示的桥梁。其核心原理包含三个要素:

  • Preview.Builder – 负责配置预览参数(分辨率、帧率、目标旋转等),生成 Preview 实例。
  • SurfaceProvider – 提供显示表面(Surface),CameraX 将相机帧渲染到该表面,通常由 PreviewView 或 Compose 的 AndroidView 包装的 SurfaceView/TextureView 提供。
  • ProcessCameraProvider – 绑定生命周期,将 Preview 用例与 Activity 或 Fragment 的生命周期关联,自动启动/停止相机。

绑定生命周期后,CameraX 内部会为 Preview 用例分配一个 CameraSession,当 SurfaceProvider 就绪时,相机帧开始流向 Surface,用户即可在屏幕上看到实时预览画面。

🔍 关键概念
SurfaceProvider 是 CameraX 1.1.0+ 引入的接口,取代了旧的 SurfaceTexture / SurfaceHolder 方式。在 Compose 中,通常通过 PreviewView 或自定义 AndroidView 的 surfaceProvider 属性获得。
⚠️ 生命周期绑定
CameraX 要求绑定 LifecycleOwner(通常是 Activity 或 Fragment)。如果使用 Compose,可以用 LocalLifecycleOwner.current 获取。生命周期不绑定的预览用例将无法启动相机。

4.2 实现流程

步骤操作说明
1获取 ProcessCameraProvider通过 ProcessCameraProvider.getInstance(context) 异步获取
2创建 Preview.Builder配置目标分辨率、帧率范围、旋转模式等
3获取 SurfaceProvider从 PreviewView 或自定义 Surface 获取
4绑定生命并启动预览调用 cameraProvider.bindToLifecycle(lifecycleOwner, cameraSelector, preview)

4.3 代码实现(Compose 环境)

以下示例展示如何在 Compose 中创建一个全屏相机预览界面,使用 PreviewView 作为 SurfaceProvider。

@Composable
fun CameraPreviewScreen() {
    val context = LocalContext.current
    val lifecycleOwner = LocalLifecycleOwner.current

    // PreviewView 暴露的 SurfaceProvider
    val previewView = remember { PreviewView(context) }

    DisposableEffect(lifecycleOwner) {
        val cameraProviderFuture = ProcessCameraProvider.getInstance(context)
        cameraProviderFuture.addListener({
            val cameraProvider = cameraProviderFuture.get()

            // 配置 Preview 用例
            val preview = Preview.Builder()
                .setTargetResolution(Size(1920, 1080))  // 目标分辨率
                .setTargetRotation(Surface.ROTATION_0)   // 主轴旋转
                .build()

            // 设置 SurfaceProvider 为 PreviewView 提供的
            preview.setSurfaceProvider(previewView.surfaceProvider)

            // 选择后置摄像头
            val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA

            // 绑定生命周期(自动管理相机)
            try {
                cameraProvider.unbindAll()
                cameraProvider.bindToLifecycle(
                    lifecycleOwner,
                    cameraSelector,
                    preview
                )
            } catch (e: Exception) {
                Log.e("CameraPreview", "绑定失败", e)
            }
        }, ContextCompat.getMainExecutor(context))

        onDispose {
            // 生命周期结束时不需要手动释放,CameraX 自动处理
        }
    }

    // 将 PreviewView 放入 Compose 树
    AndroidView(
        factory = { previewView },
        modifier = Modifier.fillMaxSize()
    )
}

4.4 SurfaceProvider 的多种获取方式

方式描述适用场景
PreviewView 自带previewView.surfaceProvider最推荐,省去手动创建 Surface
自定义 TextureView通过 TextureView.surfaceTextureListener 构造 SurfaceProvider需要定制渲染逻辑时
自定义 SurfaceView通过 SurfaceHolder 构造 SurfaceProvider需要最低延迟的渲染
❗ 常见错误:SurfaceProvider 为 null
如果在绑定生命周期之前没有调用 preview.setSurfaceProvider(),CameraX 会抛出 IllegalStateException。务必在 bindToLifecycle 之前设置。

4.5 调试与部署

  • 检查预览画面:确保 Activity 或 Fragment 的布局中包含了 PreviewView 并占据可见区域。
  • 日志输出:监听 CameraX 内部日志(通过 CameraXConfig 设置最低日志级别)或使用 android.util.Log 输出步骤信息。
  • 权限验证:AndroidManifest.xml 中必须声明 CAMERA 权限,且在运行时要动态请求。
  • 模拟器问题:Android 模拟器需要支持 Camera 模拟(AVD 配置中勾选 Camera 支持),否则预览黑屏。

4.6 性能与稳定性优化

优化项建议说明
分辨率选择根据屏幕尺寸选择合适分辨率,避免过高导致帧率下降或内存溢出通常 1280x720 或 1920x1080 足够
帧率控制通过 Preview.Builder.setTargetFrameRate() 限定帧率(如 30fps)减少不必要的渲染开销
Surface 重用避免频繁创建/销毁 SurfaceProvider,通过 PreviewView 保持 Surface 稳定CameraX 内部会做 Surface 缓存
内存监控使用 android.os.Debug 或 Profiler 检查预览时的内存占用防止内存泄漏

4.7 预览用例创建流程

下面这张流程图总结了从初始化到预览画面显示的核心步骤:

Preview 用例创建与显示流程 1. 获取 ProcessCameraProvider 2. 创建 Preview.Builder 并配置参数 3. 设置 SurfaceProvider 4. bindToLifecycle(启动相机) 5. 预览画面实时显示 ⚠️ 注意事项 1. SurfaceProvider 必须在 bind 前设置 2. 需动态申请 CAMERA 权限 💡 关键 API Preview.Builder setSurfaceProvider

4.8 常见错误与排查

错误现象可能原因解决方案
预览黑屏SurfaceProvider 未设置或设置太晚;或生命周期未绑定确保 preview.setSurfaceProvider() 在 bind 之前调用,且 lifecycleOwner 处于 Started 状态
闪退:IllegalStateException未设置 SurfaceProvider 就绑定参考上述流程顺序
预览翻转或方向错误目标旋转配置不正确根据界面方向设置 setTargetRotation() 为 Surface.ROTATION_0/90/180/270
CameraX 版本不兼容使用了过旧或过新的 API统一使用最新稳定版(如 1.3.1)并确保 Compose 版本兼容
🚀 快速验证
在 bindToLifecycle 后,可以调用 camera.cameraInfo.torchState 或 camera.cameraInfo.exposureState 确认相机是否真正启动。若获取到非 null 的 Camera 对象,说明绑定成功。

4.9 部署到真机/模拟器

  • 在 AndroidManifest.xml 中添加 <uses-permission android:name="android.permission.CAMERA" /> 及 <uses-feature android:name="android.hardware.camera" />。
  • 动态权限请求建议使用 Compose 的 rememberLauncherForActivityResult 封装,或第三方库(如 Accompanist Permissions)。
  • 模拟器预览时,请确保 AVD 的 Camera 设置为 “Webcam” 或 “Emulated”。部分模拟器不支持所有分辨率,建议先使用 Preview.Builder.setTargetResolution(Size(640,480)) 调试。

至此,你已经完成 CameraX 预览用例的创建、配置、绑定与显示。下一阶段将学习如何切换前后摄像头,以及对预览画面进行实时滤镜处理。