2. Camera API 演进:Camera1 vs Camera2 vs CameraX 架构差异与选型策略
Android 相机 API 自诞生以来经历了三次重大迭代:Camera1(旧版 API)、Camera2(新版 API)和 CameraX(Jetpack 扩展库)。每一次演进都解决了前一代的核心痛点,同时也引入了新的架构复杂度。理解这三者的差异,是正确设计预览数据通路的前提。
选型黄金法则: 新项目优先 CameraX;需要精细控制(如 RAW、多摄像头同步)时选 Camera2;Camera1 仅用于兼容 Android 4.4 以下设备或极简快照场景。
2.1 架构演进总览
下图展示了三代 API 在应用层与 HAL 层之间的架构位置与核心组件差异:
2.2 核心差异对比表
| 对比维度 | Camera1 | Camera2 | CameraX |
|---|---|---|---|
| 引入版本 | Android 1.0 (API 1) | Android 5.0 (API 21) | Android 5.0+ (Jetpack) |
| 架构模型 | 阻塞式单线程 | 异步管道 + 状态机 | UseCase 组合 + 生命周期绑定 |
| Surface 绑定方式 | setPreviewDisplay(SurfaceHolder) | Session 创建时传入 Surface 列表 | PreviewView 自动绑定 SurfaceProvider |
| 预览数据回调 | setPreviewCallback(byte[] NV21) | ImageReader Surface + OnImageAvailableListener | ImageAnalysis.Analyzer (YUV_420_888) |
| 多路输出 | 不支持(需手动拷贝) | 原生支持多 Surface | 多 UseCase 自动合并 |
| 设备兼容性 | 差(厂商定制差异大) | 中(需 LEVEL 判断) | 好(内置兼容层) |
| 生命周期管理 | 手动 onResume/onPause | 手动 open/close | 自动绑定 LifecycleOwner |
| 旋转处理 | 手动 setDisplayOrientation | 手动配置 SensorOrientation | 自动旋转 + 预览适配 |
2.3 Camera1:历史包袱与局限
Camera1 是 Android 最早的相机 API,设计上采用阻塞式单线程模型。开发者通过 android.hardware.Camera 类直接操作硬件,预览流程如下:
- 打开相机:
Camera.open()是阻塞调用,可能耗时 100-500ms。 - 配置参数: 通过
Camera.Parameters设置预览尺寸、帧率、对焦模式。 - 绑定 Surface:
setPreviewDisplay(SurfaceHolder)将预览画面输出到 SurfaceView。 - 启动预览:
startPreview()开始数据流。 - 获取帧数据:
setPreviewCallback()在预览线程中回调byte[]数据(NV21 格式)。
Camera1 致命缺陷: 预览回调运行在相机服务线程,不能做耗时操作;多路输出需要手动拷贝 NV21 数据,内存和性能开销极大;厂商定制导致
Parameters 行为不一致。
2.4 Camera2:异步管道与精细控制
Camera2 重新设计了相机架构,引入 CaptureRequest / CaptureResult 异步模型和 BufferQueue 数据通路。核心组件包括:
- CameraManager: 系统服务代理,负责枚举摄像头、获取特性。
- CameraDevice: 代表打开的相机设备,异步回调方式操作。
- CameraCaptureSession: 管理 Surface 输出管道,支持多路复用。
- CaptureRequest: 描述一次捕获的参数和目标 Surface 列表。
- ImageReader: 提供
Surface供 Session 写入,通过OnImageAvailableListener异步获取Image对象。
Camera2 预览数据通路的关键代码片段:
// 1. 获取 CameraManager
CameraManager manager = (CameraManager) getSystemService(CAMERA_SERVICE);
// 2. 打开相机(异步)
manager.openCamera(cameraId, new CameraDevice.StateCallback() {
@Override
public void onOpened(@NonNull CameraDevice camera) {
// 3. 创建 CaptureSession
List<Surface> outputs = new ArrayList<>();
Surface previewSurface = surfaceView.getHolder().getSurface();
outputs.add(previewSurface);
// 可选:ImageReader 用于帧分析
ImageReader reader = ImageReader.newInstance(width, height, ImageFormat.YUV_420_888, 2);
reader.setOnImageAvailableListener(readerListener, backgroundHandler);
outputs.add(reader.getSurface());
camera.createCaptureSession(outputs, sessionCallback, backgroundHandler);
}
}, backgroundHandler);
// 4. 发送重复预览请求
CaptureRequest.Builder builder = camera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
builder.addTarget(previewSurface);
session.setRepeatingRequest(builder.build(), null, backgroundHandler);
Camera2 优势: 原生多路 Surface 输出(预览 + 分析 + 拍照可同时进行);异步模型不阻塞 UI 线程;支持 CameraCharacteristics 查询硬件能力(如 RAW、HDR、光学防抖)。
2.5 CameraX:Jetpack 生态的易用性封装
CameraX 是 Google 在 2019 年推出的 Jetpack 相机库,本质上是 Camera2 的上层封装,但解决了 Camera2 最令人头疼的兼容性问题。其核心设计思想是 UseCase:
| UseCase | 功能 | 输出类型 | 典型场景 |
|---|---|---|---|
| Preview | 实时预览 | PreviewView(Surface) | 取景器显示 |
| ImageCapture | 拍照 | JPEG / RAW 文件 | 快门拍照 |
| ImageAnalysis | 帧分析 | ImageProxy(YUV_420_888) | 二维码扫描、人脸检测 |
| VideoCapture | 视频录制 | MediaRecorder / MediaCodec | 录像 |
CameraX 预览绑定 Surface 的代码极为简洁:
// 1. 获取 ProcessCameraProvider
ProcessCameraProvider provider = ProcessCameraProvider.getInstance(context).get();
// 2. 绑定 Preview UseCase
Preview preview = new Preview.Builder()
.setTargetResolution(new Size(1920, 1080))
.build();
// 3. 设置 SurfaceProvider(自动绑定 PreviewView)
preview.setSurfaceProvider(previewView.getSurfaceProvider());
// 4. 绑定生命周期
Camera camera = provider.bindToLifecycle(
lifecycleOwner,
CameraSelector.DEFAULT_BACK_CAMERA,
preview,
imageAnalysis // 可选:同时绑定分析 UseCase
);
CameraX 核心优势: 自动处理设备兼容性(内置 Camera2 兼容层);生命周期感知(自动释放相机资源);旋转和缩放自动适配;多 UseCase 自动合并 Surface 输出。
2.6 选型决策树
根据项目需求选择 Camera API 的决策流程:
2.7 性能与数据通路对比
从预览数据通路的视角,三代 API 在延迟、内存开销和灵活性上的差异:
| 指标 | Camera1 | Camera2 | CameraX |
|---|---|---|---|
| 预览启动延迟 | 200-500ms(阻塞) | 100-300ms(异步) | 100-250ms(异步 + 预热) |
| 帧数据获取延迟 | 高(回调线程阻塞) | 低(ImageReader 异步) | 低(ImageProxy 封装) |
| 多路输出内存 | 高(手动拷贝) | 低(共享 BufferQueue) | 低(自动合并 Surface) |
| 兼容性适配成本 | 高(每个厂商单独适配) | 中(需 LEVEL 判断 + 降级) | 低(内置兼容层) |
| 代码量(预览 + 分析) | ~200 行 | ~400 行 | ~50 行 |
数据通路关键结论: Camera2 和 CameraX 都基于 BufferQueue 实现零拷贝 Surface 传递,但 CameraX 额外封装了线程调度和生命周期管理,减少了开发者对数据通路的手动干预。Camera1 的 byte[] 回调模式在 Android 10 之后已被标记为 deprecated。
2.8 迁移建议与兼容策略
- 从 Camera1 迁移到 Camera2: 重点替换
Camera.open()为CameraManager.openCamera()异步回调;将setPreviewCallback替换为ImageReader+OnImageAvailableListener。 - 从 Camera2 迁移到 CameraX: 将
CameraDevice/CaptureSession管理替换为ProcessCameraProvider.bindToLifecycle();将ImageReader替换为ImageAnalysisUseCase。 - 混合使用: CameraX 内部仍使用 Camera2 API,可通过
CameraXConfig自定义底层 Camera2 参数(如Camera2CameraImpl)。 - 兼容性检测: 使用
CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL判断设备 Camera2 支持级别(LEGACY / LIMITED / FULL / LEVEL_3)。
注意: CameraX 目前不支持多摄像头同时打开(如前后双摄同时预览),此类场景仍需回退到 Camera2 原生 API。CameraX 的 VideoCapture UseCase 在部分设备上存在帧率不稳定问题,生产环境建议充分测试。