核心概念:CameraCaptureSession 与 CaptureRequest
在 Camera2 API 中,你并不是直接“告诉”相机拍一张照,而是创建一个“捕获请求”(CaptureRequest),并将其发送给一个“捕获会话”(CameraCaptureSession)。

(图片来源网络,侵删)
CameraCaptureSession: 这是相机与你的应用之间的桥梁,一旦你配置好这个会话,你就可以向它发送各种捕获请求(比如预览、拍照、录像)。CaptureRequest: 这是核心对象,它包含了你希望相机在下次捕获时使用的所有参数,你可以把它想象成一个“拍照指令单”,上面详细列明了 ISO、快门速度、对焦模式等所有设置。
设置参数的基本流程
- 获取相机实例: 获取
CameraDevice对象。 - 创建
CameraCaptureSession: 使用CameraDevice创建一个用于处理捕获请求的会话。 - 构建
CaptureRequest.Builder: 从CameraCaptureSession或CameraDevice创建一个CaptureRequest.Builder对象,这个构建器就像一个模板,你可以往里面添加参数。 - 设置参数: 使用
Builder提供的方法(如set(CaptureKey, value))来设置你想要的参数。 - 应用请求: 将构建好的
CaptureRequest通过CameraCaptureSession发送给相机。
详细步骤与代码示例
下面是一个完整的流程,展示了如何打开相机、创建会话,并在拍照时设置自定义参数。
添加权限和依赖
确保你的 AndroidManifest.xml 中有必要的相机权限。
<!-- AndroidManifest.xml -->
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera.any" />
<!-- 如果需要写入文件 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="28" />
获取相机管理器和打开相机
// 在你的 Activity 或 Fragment 中
private CameraManager cameraManager;
private CameraDevice cameraDevice;
private String cameraId; // "0" 表示后置摄像头
// ...
// 在 Activity 的 onCreate 或 Fragment 的 onActivityCreated 中
cameraManager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
try {
// 获取所有可用的摄像头 ID
String[] cameraIds = cameraManager.getCameraIdList();
if (cameraIds.length > 0) {
cameraId = cameraIds[0]; // 选择第一个摄像头(通常是后置)
// 打开相机设备
cameraManager.openCamera(cameraId, stateCallback, null);
}
} catch (CameraAccessException e) {
e.printStackTrace();
}
// CameraDevice.StateCallback 用于监听相机设备状态
private final CameraDevice.StateCallback stateCallback = new CameraDevice.StateCallback() {
@Override
public void onOpened(@NonNull CameraDevice camera) {
cameraDevice = camera;
// 相机打开成功,可以创建捕获会话了
createCameraCaptureSession();
}
@Override
public void onDisconnected(@NonNull CameraDevice camera) {
camera.close();
cameraDevice = null;
}
@Override
public void onError(@NonNull CameraDevice camera, int error) {
camera.close();
cameraDevice = null;
}
};
创建 CameraCaptureSession
private CameraCaptureSession captureSession;
private void createCameraCaptureSession() {
try {
// 这里我们只关注拍照,所以先创建一个用于拍照的 Surface
// 实际应用中,你可能还需要一个用于预览的 Surface
ImageReader imageReader = ImageReader.newInstance(/* 宽度 */, /* 高度 */, ImageFormat.JPEG, /* 最大图片数量 */2);
Surface captureSurface = imageReader.getSurface();
// 创建捕获会话
cameraDevice.createCaptureSession(Arrays.asList(captureSurface),
new CameraCaptureSession.StateCallback() {
@Override
public void onConfigured(@NonNull CameraCaptureSession session) {
if (cameraDevice == null) return;
captureSession = session;
// 会话配置完成,可以开始拍照了
takePicture();
}
@Override
public void onConfigureFailed(@NonNull CameraCaptureSession session) {
// 会话配置失败
}
}, null);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
构建并应用 CaptureRequest (核心部分)
这是设置参数的关键步骤,我们将在 takePicture() 方法中实现。
private void takePicture() {
if (cameraDevice == null || captureSession == null) return;
try {
// 1. 创建一个用于拍照的 CaptureRequest.Builder
// 我们传入 TEMPLATE_STILL_CAPTURE,这是一个专门为静态拍照优化的模板
CaptureRequest.Builder captureRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
// 2. 设置目标 Surface
// 这个 Surface 来自于 ImageReader,用于接收拍照后的 JPEG 数据
captureRequestBuilder.addTarget(imageReader.getSurface());
// 3. 设置各种拍照参数 (重点!)
// -----------------------------------------------------------------
// 设置闪光灯模式
captureRequestBuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_AUTO);
// 设置曝光模式
captureRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
// 设置对焦模式
// 如果设备支持连续对焦,可以在拍照前先对焦
captureRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
// 在拍照瞬间,可以切换为自动对焦
// captureRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_AUTO);
// 或者锁定对焦
// captureRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CaptureRequest.CONTROL_AF_TRIGGER_START);
// 设置白平衡模式
captureRequestBuilder.set(CaptureRequest.CONTROL_AWB_MODE, CaptureRequest.CONTROL_AWB_MODE_AUTO);
// 设置感光度 (ISO)
// 注意:ISO 通常由 AE (自动曝光) 模式控制,手动设置需要特定的 AE 模式
// captureRequestBuilder.set(CaptureRequest.SENSOR_SENSITIVITY, 800); // 例如设置为 ISO 800
// 设置曝光时间 (快门速度)
// 同样,这通常也由 AE 模式控制
// captureRequestBuilder.set(CaptureRequest.SENSOR_EXPOSURE_TIME, 1000000); // 1/1000 秒 (单位: 纳秒)
// 设置 JPEG 质量 (0-100)
captureRequestBuilder.set(CaptureRequest.JPEG_QUALITY, (byte) 90); // 90% 质量
// 设置照片的旋转角度,确保照片方向正确
int rotation = getWindowManager().getDefaultDisplay().getRotation();
int sensorOrientation = cameraManager.getCameraCharacteristics(cameraId).get(CameraCharacteristics.SENSOR_ORIENTATION);
int jpegRotation = (sensorOrientation + rotation * 90) % 360;
captureRequestBuilder.set(CaptureRequest.JPEG_ORIENTATION, jpegRotation);
// 如果需要锁定 AE 和 AF,在拍照前调用
// captureRequestBuilder.set(CaptureRequest.CONTROL_AE_LOCK, true);
// captureRequestBuilder.set(CaptureRequest.CONTROL_AF_LOCK, true);
// -----------------------------------------------------------------
// 4. 发送捕获请求
// 使用 REPEATABLE 模式,这样如果会话没有重建,这个请求可以被重复使用
// 对于单次拍照,使用 CAPTURE_MODE_ONE_SHOT 也可以
captureSession.capture(captureRequestBuilder.build(), new CameraCaptureSession.CaptureCallback() {
@Override
public void onCaptureCompleted(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull TotalCaptureResult result) {
// 拍照完成,可以在这里处理结果,例如释放锁
// request.set(CaptureRequest.CONTROL_AE_LOCK, false);
// request.set(CaptureRequest.CONTROL_AF_LOCK, false);
Log.d("Camera", "Picture captured successfully!");
}
}, null);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
常用参数一览表
| 参数类别 | CaptureRequest 键 |
值类型 | 说明 |
|---|---|---|---|
| 曝光 | CONTROL_AE_MODE |
int |
自动曝光模式。ON_AUTO_FLASH, ON_ALWAYS_FLASH, OFF 等。 |
CONTROL_AE_LOCK |
boolean |
锁定自动曝光。 | |
SENSOR_EXPOSURE_TIME |
long |
曝光时间(纳秒),手动模式时有效。 | |
SENSOR_SENSITIVITY |
int |
感光度,手动模式时有效。 | |
| 对焦 | CONTROL_AF_MODE |
int |
自动对焦模式。CONTINUOUS_PICTURE, AUTO, MACRO 等。 |
CONTROL_AF_TRIGGER |
int |
触发对焦。AF_TRIGGER_START, AF_TRIGGER_CANCEL。 |
|
CONTROL_AF_LOCK |
boolean |
锁定自动对焦。 | |
| 闪光灯 | FLASH_MODE |
int |
闪光灯模式。FLASH_MODE_OFF, FLASH_MODE_AUTO, FLASH_MODE_ON。 |
| 白平衡 | CONTROL_AWB_MODE |
int |
自动白平衡模式。AUTO, INCANDESCENT, DAYLIGHT 等。 |
CONTROL_AWB_LOCK |
boolean |
锁定自动白平衡。 | |
| 输出 | JPEG_QUALITY |
byte |
JPEG 图像质量 (0-100)。 |
JPEG_ORIENTATION |
int |
JPEG 图像的旋转角度 (0, 90, 180, 270)。 | |
JPEG_THUMBNAIL_QUALITY |
byte |
JPEG 缩略图质量 (0-100)。 | |
| 控制 | CONTROL_MODE |
int |
同时控制 AE 和 AF,通常设为 USE_SCENE_MODE 或 OFF。 |
重要注意事项
- 异步操作:
Camera2API 是完全异步的,所有耗时操作(如打开相机、配置会话)都必须通过回调来完成,绝不能在主线程中调用。 - 模板:
createCaptureRequest()需要一个模板参数,不同的模板(TEMPLATE_PREVIEW,TEMPLATE_STILL_CAPTURE,TEMPLATE_RECORD)会预置一组不同的参数,这能让你更快地达到预期的效果。TEMPLATE_PREVIEW: 优化预览速度和帧率。TEMPLATE_STILL_CAPTURE: 优化静态照片的质量,通常会牺牲一些速度。TEMPLATE_RECORD: 优化视频录制。
- 设备能力检查: 不是所有设备都支持所有参数,在设置参数前,应该先检查设备是否支持。
CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(cameraId); // 检查是否支持手动曝光 if (characteristics.get(CameraCharacteristics.CONTROL_AE_AVAILABLE_MODES).contains(CaptureRequest.CONTROL_AE_MODE_OFF)) { // 设备支持手动模式,可以设置 SENSOR_EXPOSURE_TIME 和 SENSOR_SENSITIVITY } - 资源管理: 在 Activity/Fragment 销毁时,必须正确关闭所有相机资源,否则会导致内存泄漏和崩溃。
@Override protected void onDestroy() { super.onDestroy(); if (captureSession != null) { captureSession.close(); captureSession = null; } if (cameraDevice != null) { cameraDevice.close(); cameraDevice = null; } // 关闭 ImageReader if (imageReader != null) { imageReader.close(); imageReader = null; } }
替代方案:CameraX (推荐给新项目)
如果你觉得 Camera2 API 太复杂,Google 推荐了 CameraX 库,它是对 Camera2 的一层高级封装,极大地简化了代码。

(图片来源网络,侵删)
使用 CameraX 设置参数非常简单:
// 1. 创建 Preview 用例
Preview preview = new Preview.Builder().build();
// 2. 创建 ImageCapture 用例
ImageCapture imageCapture = new ImageCapture.Builder()
.setFlashMode(ImageCapture.FLASH_MODE_AUTO) // 设置闪光灯
.setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY) // 设置捕获模式
.setJpegQuality(90) // 设置 JPEG 质量
.build();
// 3. 绑定到生命周期
CameraX.bindToLifecycle(this, preview, imageCapture);
// 4. 拍照
imageCapture.takePicture(executor, new ImageCapture.OnImageCapturedCallback() {
@Override
public void onCaptureSuccess(@NonNull ImageProxy image) {
// 获取到图片数据,进行处理或保存
// ...
}
@Override
public void onError(@NonNull ImageCaptureException exc) {
// 处理错误
}
});
- 对于需要精细控制、高性能或兼容旧设备的项目,直接使用
Camera2API 是必经之路。 - 对于大多数新项目,尤其是想快速开发、减少复杂性的项目,强烈推荐使用 CameraX,它提供了更简洁、更现代的 API,但底层仍然是
Camera2。

(图片来源网络,侵删)
