3. CameraX 核心组件详解:Preview、ImageCapture、ImageAnalysis、CameraSelector、UseCase 绑定与组合

CameraX 是 Google 推出的 Jetpack 相机库,旨在简化 Android 相机开发。其核心设计思想是 UseCase(用例) 模式——将相机功能抽象为独立的、可组合的模块。本章深入剖析 CameraX 的五大核心组件:Preview、ImageCapture、ImageAnalysis、CameraSelector,以及如何通过 ProcessCameraProvider 进行 UseCase 的绑定与组合。

3.1 CameraX 架构总览

CameraX 采用 生命周期感知 与 用例驱动 的架构。开发者无需直接管理 CameraSession,只需声明需要哪些功能(UseCase),CameraX 自动处理相机设备选择、配置、生命周期绑定与资源释放。

核心原则: 一个 CameraX 实例可以同时绑定多个 UseCase,只要它们不冲突(如同时使用两个 ImageCapture 会报错)。系统会根据绑定的 UseCase 自动协商最优的相机配置(分辨率、帧率、格式)。
CameraX 架构分层图 应用层(Activity / Fragment / ViewModel) UseCase 层 Preview ImageCapture ImageAnalysis VideoCapture CameraX 核心层(ProcessCameraProvider / Camera / CameraInfo) 系统层(Camera HAL / Camera Service / 硬件)

3.2 核心 UseCase 详解

3.2.1 Preview(预览)

Preview 负责将相机实时画面显示到 PreviewView 上。它是所有相机应用的基础 UseCase。

  • 关键配置: 通过 Preview.Builder 设置分辨率、目标旋转角度、相机模式(如 CAMERA_EFFECT)。
  • SurfaceProvider: Preview 不直接操作 SurfaceView/TextureView,而是通过 SurfaceProvider 接口与 UI 层解耦。
  • 性能优化: 建议使用 PreviewView(CameraX 提供的专用 View),它内部自动处理了 Surface 生命周期与缩放。
// Preview 创建与配置示例
Preview preview = new Preview.Builder()
    .setTargetResolution(new Size(1920, 1080))
    .setTargetRotation(Surface.ROTATION_0)
    .build();

// 将 PreviewView 的 SurfaceProvider 绑定到 Preview
preview.setSurfaceProvider(previewView.getSurfaceProvider());

3.2.2 ImageCapture(拍照)

ImageCapture 提供拍照功能,支持 JPEG 和 RAW 格式输出。它是扫码相机和文档扫描应用的核心拍照组件。

  • 拍照模式: 支持 CAPTURE_MODE_MINIMIZE_LATENCY(低延迟)和 CAPTURE_MODE_MAXIMIZE_QUALITY(高质量)。
  • 闪光灯控制: 通过 setFlashMode() 设置自动、开启、关闭。
  • 输出选项: 可指定文件保存路径(OutputFileOptions)或内存中的 ImageProxy。
// ImageCapture 创建与拍照示例
ImageCapture imageCapture = new ImageCapture.Builder()
    .setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY)
    .setFlashMode(ImageCapture.FLASH_MODE_AUTO)
    .build();

// 拍照并保存到文件
File photoFile = new File(getExternalFilesDir(null), "photo.jpg");
ImageCapture.OutputFileOptions outputOptions =
    new ImageCapture.OutputFileOptions.Builder(photoFile).build();
imageCapture.takePicture(outputOptions, ContextCompat.getMainExecutor(this),
    new ImageCapture.OnImageSavedCallback() {
        @Override
        public void onImageSaved(@NonNull ImageCapture.OutputFileResults output) {
            // 拍照成功
        }
        @Override
        public void onError(@NonNull ImageCaptureException exception) {
            // 拍照失败
        }
    });

3.2.3 ImageAnalysis(图像分析)

ImageAnalysis 提供连续的帧数据流,用于实时分析(如扫码、人脸检测、文档边缘识别)。它是扫码相机应用的核心。

  • 分析模式: STRATEGY_KEEP_ONLY_LATEST(只保留最新帧,丢弃旧帧)和 STRATEGY_BLOCK_PRODUCER(阻塞生产者直到分析完成)。扫码场景推荐使用 KEEP_ONLY_LATEST。
  • 图像格式: 默认输出 YUV_420_888 格式的 ImageProxy。
  • 线程管理: 分析器在独立的后台线程中执行,不会阻塞 UI 线程。
// ImageAnalysis 创建与帧分析示例
ImageAnalysis imageAnalysis = new ImageAnalysis.Builder()
    .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
    .setTargetResolution(new Size(1280, 720))
    .build();

imageAnalysis.setAnalyzer(Executors.newSingleThreadExecutor(), imageProxy -> {
    // 在后台线程处理每一帧
    // 对于扫码场景,将 imageProxy 传递给 ML Kit 或 ZXing 解码器
    imageProxy.close(); // 必须关闭,否则会阻塞后续帧
});
性能提示: 在 ImageAnalysis 的 Analyzer 中,务必在分析完成后调用 imageProxy.close()。如果使用 STRATEGY_BLOCK_PRODUCER 且不关闭,会导致相机帧生产被永久阻塞。

3.2.4 CameraSelector(相机选择器)

CameraSelector 用于选择使用哪个物理相机(后置、前置、外接)。CameraX 提供了默认选择器,也支持自定义筛选逻辑。

选择器类型 说明 适用场景
DEFAULT_BACK_CAMERA 默认后置摄像头 文档扫描、扫码、普通拍照
DEFAULT_FRONT_CAMERA 默认前置摄像头 自拍、视频通话
自定义 CameraSelector 通过 CameraSelector.Builder 添加 CameraFilter 筛选 需要特定镜头(如超广角、长焦)
// 使用默认后置摄像头
CameraSelector cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA;

// 自定义筛选:优先使用后置主摄,若不可用则回退
CameraSelector customSelector = new CameraSelector.Builder()
    .requireLensFacing(CameraSelector.LENS_FACING_BACK)
    .addCameraFilter(cameraInfos -> {
        // 自定义筛选逻辑,返回最合适的 CameraInfo 列表
        return cameraInfos;
    })
    .build();

3.3 UseCase 绑定与组合

CameraX 的核心能力在于 多 UseCase 组合。通过 ProcessCameraProvider 将多个 UseCase 绑定到同一个生命周期,系统自动协商最优配置。

3.3.1 绑定流程

  1. 获取 ProcessCameraProvider 实例(通过 ProcessCameraProvider.getInstance(context))。
  2. 创建所需的 UseCase 实例(Preview、ImageCapture、ImageAnalysis 等)。
  3. 创建 CameraSelector 选择相机。
  4. 调用 cameraProvider.bindToLifecycle(lifecycleOwner, cameraSelector, useCases...) 绑定。
  5. 绑定成功后返回 Camera 对象,可用于控制变焦、闪光灯、对焦等。
// 完整绑定示例:同时绑定 Preview + ImageCapture + ImageAnalysis
ProcessCameraProvider cameraProvider = ProcessCameraProvider.getInstance(this).get();

// 创建 UseCase
Preview preview = new Preview.Builder().build();
ImageCapture imageCapture = new ImageCapture.Builder().build();
ImageAnalysis imageAnalysis = new ImageAnalysis.Builder()
    .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
    .build();

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

// 绑定到生命周期
Camera camera = cameraProvider.bindToLifecycle(
    this,               // LifecycleOwner
    cameraSelector,     // 相机选择器
    preview,            // 预览
    imageCapture,       // 拍照
    imageAnalysis       // 图像分析
);

// 绑定后设置 Preview 的 SurfaceProvider
preview.setSurfaceProvider(previewView.getSurfaceProvider());

3.3.2 UseCase 组合策略

不同的应用场景需要不同的 UseCase 组合。以下是常见组合及其适用场景:

组合模式 包含 UseCase 典型应用 注意事项
基础预览 Preview 简单相机预览 最低资源消耗
扫码相机 Preview + ImageAnalysis 二维码/条形码扫描 ImageAnalysis 使用 KEEP_ONLY_LATEST 策略
文档扫描 Preview + ImageCapture + ImageAnalysis 文档边缘检测 + 拍照 ImageAnalysis 用于实时边缘检测,ImageCapture 用于最终拍照
高清拍照 Preview + ImageCapture 普通拍照应用 ImageCapture 使用 MAXIMIZE_QUALITY 模式
视频录制 Preview + VideoCapture 视频录制应用 VideoCapture 需要额外配置 MediaRecorder
UseCase 组合与数据流图(扫码相机场景) 相机硬件(HAL) CameraX 核心(ProcessCameraProvider) Preview SurfaceProvider ImageCapture 拍照输出 ImageAnalysis 帧分析 PreviewView 显示 JPEG 文件 / Bitmap 扫码结果回调 三个 UseCase 同时绑定到同一个 CameraX 生命周期,共享同一相机会话

3.4 UseCase 冲突与协商机制

当绑定多个 UseCase 时,CameraX 会自动进行 配置协商,确保所有 UseCase 都能正常工作。如果存在不可调和的冲突,bindToLifecycle 会抛出 IllegalArgumentException。

常见冲突场景:
  • 同时绑定两个 ImageCapture 或两个 ImageAnalysis(同一类型 UseCase 只能有一个)。
  • 绑定的 UseCase 要求的分辨率或帧率超出相机硬件能力。
  • 同时绑定 VideoCapture 和 ImageAnalysis 时,某些设备可能不支持同时输出两种格式。

3.4.1 协商优先级

CameraX 的协商策略遵循以下优先级:

  1. Preview 的分辨率优先满足 PreviewView 的尺寸。
  2. ImageCapture 的分辨率优先满足设定的 targetResolution,若无法满足则降级。
  3. ImageAnalysis 的分辨率在满足前两者后取剩余能力,通常建议设置较小的分辨率(如 640x480)以提高分析速度。

3.5 生命周期管理与解绑

CameraX 自动感知 LifecycleOwner 的生命周期:

  • onStart: 打开相机会话。
  • onResume: 恢复预览和帧分析。
  • onPause: 暂停预览和帧分析。
  • onStop: 关闭相机会话,释放资源。
  • onDestroy: 完全解绑 UseCase。

如果需要手动解绑(例如切换相机),调用 cameraProvider.unbindAll() 或 cameraProvider.unbind(useCases...)。

// 手动解绑所有 UseCase
cameraProvider.unbindAll();

// 解绑特定 UseCase(例如只移除 ImageAnalysis)
cameraProvider.unbind(imageAnalysis);

// 解绑后重新绑定新的 UseCase 组合
Camera camera = cameraProvider.bindToLifecycle(
    this, cameraSelector, preview, imageCapture
);

3.6 本章小结

  • Preview 负责实时预览,通过 SurfaceProvider 与 UI 解耦。
  • ImageCapture 提供拍照功能,支持低延迟和高质量两种模式。
  • ImageAnalysis 提供连续帧分析,是扫码和文档检测的核心。
  • CameraSelector 用于选择后置/前置/自定义相机。
  • UseCase 绑定 通过 ProcessCameraProvider.bindToLifecycle() 实现,支持灵活组合。
  • CameraX 自动处理 配置协商 和 生命周期管理,大幅降低开发复杂度。