Android Camera2 API:解锁屏幕后onImageAvailable()函数未触发问题咨询
嘿,这个问题我之前帮好几个开发者排查过,确实是Camera2 API里一个容易被忽略的场景,连官方Demo都没处理到位,太坑了😂
问题根源与修复方案
核心原因
锁屏操作会触发Android系统对相机资源的强制调度:系统可能会临时关闭相机设备、销毁已创建的CaptureSession,但官方Demo没有监听这些状态变化,也没有在解锁后重新建立ImageReader与相机的回调链路,导致onImageAvailable()彻底“失联”。
具体修复步骤
1. 监听锁屏/解锁事件,触发相机重初始化
先注册系统广播监听屏幕状态,在解锁时重新拉起相机流程:
// Kotlin示例:注册屏幕状态广播 private val screenStateReceiver = object : BroadcastReceiver() { override fun onReceive(context: Context?, intent: Intent?) { when (intent?.action) { Intent.ACTION_SCREEN_ON -> { // 屏幕解锁,检查相机状态并重建 if (cameraDevice == null || !cameraDevice!!.isOpen) { openCamera() } else { recreateCaptureSession() } } Intent.ACTION_SCREEN_OFF -> { // 锁屏时主动清理相机资源,避免冲突 closeCameraSafely() } } } } // 在Activity的onCreate中注册广播 override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val filter = IntentFilter().apply { addAction(Intent.ACTION_SCREEN_ON) addAction(Intent.ACTION_SCREEN_OFF) } registerReceiver(screenStateReceiver, filter) }
2. 重建CaptureSession时,重新绑定ImageReader的Surface
每次创建CaptureSession都要重新获取ImageReader的Surface引用,不要复用旧对象:
// Java示例:重建CaptureSession private void recreateCaptureSession() { Surface previewSurface = mPreviewView.getSurface(); Surface imageReaderSurface = mImageReader.getSurface(); List<Surface> targetSurfaces = Arrays.asList(previewSurface, imageReaderSurface); try { mCameraDevice.createCaptureSession(targetSurfaces, new CameraCaptureSession.StateCallback() { @Override public void onConfigured(@NonNull CameraCaptureSession session) { mCaptureSession = session; // 重新启动预览流 startRepeatingPreview(); } @Override public void onConfigureFailed(@NonNull CameraCaptureSession session) { // 处理配置失败逻辑,比如弹出提示 } }, null); } catch (CameraAccessException e) { e.printStackTrace(); } }
3. 重启重复预览请求,恢复帧回调
在startRepeatingPreview()中,重新构建CaptureRequest并提交,确保ImageReader能收到新帧:
private fun startRepeatingPreview() { val requestBuilder = cameraDevice?.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW) ?: return // 重新添加ImageReader和预览View的Surface requestBuilder.addTarget(imageReader.surface) requestBuilder.addTarget(previewView.surface) captureSession?.setRepeatingRequest( requestBuilder.build(), null, // 不需要单独的捕获回调,用ImageReader的onImageAvailable即可 backgroundHandler ) }
4. 安全清理旧资源,避免内存泄漏
锁屏时主动关闭CaptureSession和CameraDevice,防止资源冲突:
private fun closeCameraSafely() { captureSession?.apply { stopRepeating() abortCaptures() close() } cameraDevice?.close() captureSession = null cameraDevice = null }
额外注意事项
- 不同厂商的设备相机行为可能有差异,部分设备锁屏时不会直接关闭相机,但会暂停预览流,统一处理锁屏事件能覆盖更多场景;
- Android 10+系统对相机权限管控更严格,确保在解锁后重新检查相机权限状态;
ImageReader.setMaxImages()的数值不要设置过大,避免内存占用过高,一般设置为2-3即可满足预览需求。
内容的提问来源于stack exchange,提问作者wkurek
相关产品推荐
相关产品推荐

