第1章:Camera2 API架构——核心类解析
说实话,刚接触Camera2的时候,我也挺懵的。
五个核心类,名字还都带个"Camera",看着就头大。但你别怕,这东西说白了就是一套流程——打开相机、配置参数、发起请求、拿到结果。我做了这么多年摄像头开发,今天就把这套流程给你拆开揉碎了讲清楚。
1.1 CameraManager——相机管家
CameraManager是系统的相机服务管理器。它的职责很简单:发现相机、打开相机。
我个人习惯把CameraManager理解成"酒店前台"。你想开房(打开相机),得先找前台问问有没有空房(获取相机列表),然后前台给你房卡(CameraDevice)。
核心方法:
getCameraIdList()——获取所有相机IDgetCameraCharacteristics(String cameraId)——获取相机特性openCamera(String cameraId, CameraDevice.StateCallback callback, Handler handler)——打开相机
嗯,这里要注意:openCamera()是异步的。你调用之后不会立刻拿到CameraDevice,而是通过回调告诉你"房卡准备好了"。我在项目中遇到过新手直接拿null去操作,结果崩溃得一塌糊涂。
// 获取CameraManager
CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
// 获取相机ID列表
String[] cameraIds = manager.getCameraIdList();
// 打开后置摄像头
manager.openCamera("0", new CameraDevice.StateCallback() {
@Override
public void onOpened(@NonNull CameraDevice camera) {
// 相机打开了,可以干活了
}
@Override
public void onDisconnected(@NonNull CameraDevice camera) {
// 相机断开了
}
@Override
public void onError(@NonNull CameraDevice camera, int error) {
// 出错了
}
}, null);
1.2 CameraDevice——相机设备
CameraDevice代表一个物理相机。拿到它之后,你才能做真正的操作——比如创建会话、发起拍照请求。
你可以把它想象成"房卡"。有了房卡,你才能进房间(创建CaptureSession),才能开灯、调空调(设置参数)。
我的经验:CameraDevice是重量级资源,用完后一定要调用close()释放。我曾经在早期项目里忘记释放,结果相机被占着,其他应用打不开,用户直接给了一星差评。
CameraDevice的核心方法就两个:
createCaptureSession()——创建捕获会话createCaptureRequest(int templateType)——创建捕获请求模板
1.3 CameraCaptureSession——捕获会话
这个类管理着相机数据的"管道"。说白了,它决定了数据怎么流、流到哪里去。
你想想看,相机每秒可能产生30帧甚至60帧数据。这些数据要送到预览Surface、拍照的ImageReader、视频编码器……谁来调度?就是CameraCaptureSession。
核心方法:
setRepeatingRequest()——发起持续请求(预览用)capture()——发起单次请求(拍照用)abortCaptures()——中止所有请求
我记得有一次调试预览卡顿,查了半天发现是setRepeatingRequest()和capture()混用导致冲突。后来我养成了习惯:预览只用setRepeatingRequest(),拍照单独走capture(),互不干扰。
1.4 CaptureRequest——捕获请求
CaptureRequest就是你要告诉相机"怎么拍"的指令集。它包含:
- 输出目标(Surface列表)
- 各种参数(对焦、曝光、白平衡等)
你可以通过Builder模式来构建它:
// 创建预览请求
CaptureRequest.Builder builder = cameraDevice.createCaptureRequest(
CameraDevice.TEMPLATE_PREVIEW);
builder.addTarget(previewSurface);
builder.set(CaptureRequest.CONTROL_AF_MODE,
CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
CaptureRequest request = builder.build();
这里有个坑:Builder只能用一次。你调用build()之后,如果想改参数,必须重新创建Builder。我曾经踩过这个坑,以为可以复用,结果参数死活改不了。
1.5 CaptureResult——捕获结果
CaptureResult是相机给你的"答卷"。它告诉你:
- 实际用了什么参数(可能和你设置的不一样)
- 当前状态(对焦是否完成、曝光是否正常)
- 元数据(时间戳、传感器信息等)
你通过CameraCaptureSession.CaptureCallback来接收结果:
session.setRepeatingRequest(request, new CameraCaptureSession.CaptureCallback() {
@Override
public void onCaptureCompleted(@NonNull CameraCaptureSession session,
@NonNull CaptureRequest request, @NonNull TotalCaptureResult result) {
// 拿到结果了
Integer afState = result.get(CaptureResult.CONTROL_AF_STATE);
// 根据对焦状态做后续处理
}
}, null);
注意:CaptureResult是异步回调回来的。不要在回调里做耗时操作,否则会阻塞相机管道。我见过有人直接在回调里写文件,结果预览帧率掉到个位数。
1.6 核心流程总结
这五个类的关系,我用一张图给你画清楚:
流程其实就三步:
- CameraManager帮你找到并打开相机,拿到CameraDevice
- CameraDevice创建CaptureRequest和CameraCaptureSession
- CameraCaptureSession把请求发出去,通过回调拿到CaptureResult
避坑指南:我曾经在项目里把CameraDevice.StateCallback写成匿名内部类,结果导致内存泄漏。后来我改成成员变量,并在onDisconnected()和onError()里做好清理。记住:相机资源一定要及时释放。
好了,这五个核心类的关系和用法,你应该心里有数了。下一章我们开始实战——写一个完整的预览+拍照Demo。
公众号:蓝海资料掘金营,微信deep3321