You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 04:01:49