Camera2框架下ImageReader无法读取图像,添加后应用崩溃求助
Camera2框架ImageReader捕获图像崩溃问题解决
核心问题分析
错误码4对应ERROR_INVALID_ARGUMENT,本质是ImageReader的配置与相机输出不兼容,或是会话创建与请求配置的Surface逻辑不匹配:只把ImageReader加入会话但未在请求中指定输出,监听器自然不会触发;若直接在请求中添加未纳入会话的Surface,或尺寸/格式不兼容,就会触发参数无效崩溃。
分步解决方案
1. 确保ImageReader配置符合相机支持的输出参数
不要硬编码尺寸和格式,先从相机特性中获取兼容配置:
val cameraManager = getSystemService(Context.CAMERA_SERVICE) as CameraManager val characteristics = cameraManager.getCameraCharacteristics(cameraId) val configMap = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP)!! // 获取相机支持的YUV格式输出尺寸(建议用YUV_420_888,兼容性最好) val supportedSizes = configMap.getOutputSizes(ImageFormat.YUV_420_888) // 选择与SurfaceView尺寸最接近的尺寸,避免缩放报错 val targetSize = supportedSizes.firstOrNull { it.width == surfaceView.width && it.height == surfaceView.height } ?: supportedSizes[0] // 创建ImageReader,最大缓存2帧避免内存溢出 val imageReader = ImageReader.newInstance( targetSize.width, targetSize.height, ImageFormat.YUV_420_888, 2 )
2. 严格遵循会话与请求的Surface关联逻辑
- 创建会话时,必须把**所有需要接收相机数据的Surface(SurfaceView + ImageReader)**都传入集合:
- 在预览请求中添加需要输出的Surface,同时确保参数配置正确:
val surfaces = listOf(surfaceView.holder.surface, imageReader.surface) cameraDevice.createCaptureSession(surfaces, object : CameraCaptureSession.StateCallback() { override fun onConfigured(session: CameraCaptureSession) { // 构建预览请求 val previewRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW) // 添加SurfaceView用于预览显示 previewRequestBuilder.addTarget(surfaceView.holder.surface) // 添加ImageReader用于持续捕获图像(如果是拍照时才捕获,就只在拍照请求中添加) previewRequestBuilder.addTarget(imageReader.surface) // 开启自动对焦,提升预览体验 previewRequestBuilder.set( CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE ) // 启动重复预览请求 session.setRepeatingRequest( previewRequestBuilder.build(), null, Handler(Looper.getMainLooper()) ) } override fun onConfigureFailed(session: CameraCaptureSession) { // 处理会话配置失败逻辑,比如弹出提示 } }, Handler(Looper.getMainLooper()))
3. 正确设置ImageReader监听器
提前设置监听器,避免错过图像回调,且必须及时关闭Image对象防止内存泄漏:
imageReader.setOnImageAvailableListener({ reader -> val image = reader.acquireLatestImage() ?: return@setOnImageAvailableListener // 这里处理图像数据,比如转Bitmap、保存文件等 // 处理完成后必须关闭Image image.close() }, Handler(Looper.getMainLooper()))
4. 模拟器适配注意事项
Pixel 3a API31模拟器的Camera2支持有限,需额外注意:
- 确保模拟器相机设置为「虚拟场景」或已连接物理相机
- 避免使用过高分辨率,优先选择模拟器支持的中等尺寸
关键逻辑澄清
- 会话是输出通道集合:所有要接收相机数据的Surface必须先加入CaptureSession,否则无法在请求中使用
- 请求指定输出目标:只有在CaptureRequest中添加已纳入会话的Surface,相机才会向该Surface输出数据
- 两者必须严格匹配,否则要么监听器无回调,要么触发参数无效崩溃
内容的提问来源于stack exchange,提问作者deadfish
相关产品推荐
相关产品推荐

