Administrator
发布于 2026-08-06 / 16 阅读
0
0

Camera2预览卡顿、对焦抖动、内存泄漏、拍照黑屏这些常见问题怎么排查?

针对 Camera2 框架中这四个最常见的“顽疾”,其根本原因通常都出在流水线(Pipeline)的阻塞、状态错乱或资源未释放。

以下是针对每个问题的核心原因分析与排查止血方案:


1. 预览卡顿 (Preview Lag / Stutter)

预览卡顿通常是因为主线程(UI线程)被阻塞,或者相机输出的分辨率过高导致硬件处理不过来。

  • 核心原因排查:

    • Handler 绑定错误:检查 openCamera、createCaptureSession 和 setRepeatingRequest 中传入的最后一个参数 Handler。如果传了 null 或 new Handler(Looper.getMainLooper()),相机的所有回调(包括每一帧的数据解析)都会挤在主线程执行。

    • 分辨率不匹配:输出的 Surface(如 TextureView)的分辨率与相机支持的预览分辨率(通过 StreamConfigurationMap 获取)不匹配,导致系统在底层频繁进行缩放(Scaling)操作。

    • 数据处理太重:如果在 ImageReader.OnImageAvailableListener 中直接写了耗时的图像分析算法(如人脸识别、格式转换),且没有异步处理,会直接拖慢整条流水线。

  • 解决方案:

    • 使用独立后台线程:必须创建一个专门的 HandlerThread 供相机后台回调使用。

    • 及时关闭 Image:在 onImageAvailable 中,处理完数据后必须立刻调用 image.close(),否则下一帧无法塞入队列,导致流水线阻塞。


2. 对焦抖动 (Focus Hunting / Jitter)

对焦抖动表现为画面频繁忽明忽暗、反复拉伸风箱,无法稳定锁定焦点。

  • 核心原因排查:

    • 对焦模式选错:在预览的 CaptureRequest 中,错误地在 CONTROL_AF_MODE_AUTO(手动触发对焦)和 CONTROL_AF_MODE_CONTINUOUS_PICTURE(持续自动对焦)之间频繁切换或混用。

    • 重复触发对焦触发器:在 setRepeatingRequest 的循环请求中,错误地写入了 CaptureRequest.CONTROL_AF_TRIGGER_START。这会导致相机每一帧都在重新初始化对焦流程。

  • 解决方案:

    • 保持持续对焦:日常预览时,只需设置一次 CONTROL_AF_MODE_CONTINUOUS_PICTURE,不要带上 AF_TRIGGER。

    • 正确手动对焦(测光):触发点击对焦时,先发送一个单次请求(capture)去触发 CONTROL_AF_TRIGGER_START,等待 CaptureResult 返回对焦成功(AF_STATE_FOCUSED_LOCKED)后,立刻将触发器重置为 CONTROL_AF_TRIGGER_IDLE 发回预览,否则相机会锁死在当前状态。


3. 内存泄漏 (Memory Leak)

Camera2 涉及大量系统底层硬件服务的映射,一旦发生内存泄漏,轻则手机发烫,重则下次打开相机直接报 CameraAccessException: Camera in use 或系统 OOM。

  • 核心原因排查:

    • 生命周期未闭环:Activity/Fragment 销毁时,没有依次关闭会话和设备。

    • 异步回调持有 Context:传入相机的自定义 StateCallback 或 Handler 隐式持有了外部 Activity 的引用,导致 Activity 无法被 GC 回收。

  • 解决方案(标准销毁序列):

    • 在 onPause() 或 onDestroy() 中,必须严格执行以下反向释放流程:

      // 1. 停止预览循环
      captureSession?.stopRepeating()
      // 2. 关闭会话
      captureSession?.close()
      captureSession = null
      // 3. 关闭相机设备
      cameraDevice?.close()
      cameraDevice = null
      // 4. 关闭 ImageReader 等资源
      imageReader?.close()
      // 5. 退出后台线程
      backgroundThread?.quitSafely()
      

4. 拍照黑屏 (Black Screen on Capture)

点击拍照瞬间,画面突然变黑,或者最终保存出来的图片是一张全黑图。

  • 核心原因排查:

    • Surface 目标丢失:在构建拍照的 CaptureRequest 时,忘记添加拍照的输出端(如 ImageReader.surface),或者错误地把预览的 Surface 当作了拍照的输出端。

    • 闪光灯与曝光同步失败:开启闪光灯拍照时,没有进行前置测光(Pre-capture Metering),导致相机在闪光灯还没亮起或已经熄灭的瞬间闭合了快门。

    • 底层硬件配置级别不够(Legacy 设备):部分老旧手机硬件级别为 LEGACY,它们不支持在拍照时同时维持预览输出。一旦调用 capture(),预览流会被强制中断,处理不当就会黑屏。

  • 解决方案:

    • 检查 Target:确保拍照的 Request 中包含了正确的 ImageReader.surface:photoBuilder.addTarget(imageReader.surface)。

    • 标准拍照预检查流水线:如果是高要求拍照,遵循官方标准流程:

      1. 发送 AF_TRIGGER_START 锁定对焦。

      2. 发送 AE_PRECAPTURE_TRIGGER_START 锁定曝光与闪光灯测光。

      3. 收到测光完成回调后,再发送最终的拍照 capture()。

      4. 拍照完成后,发送 AE/AF_TRIGGER_CANCEL 恢复预览。


💡 一个终极排查建议:利用官方工具

如果你被 Camera2 的复杂状态搞晕了,推荐在代码中引入 CameraX 的 Camera2Interop 工具,或者在排查阶段直接使用 Google 官方的开源相机库 Camera2Basic 作为标准参照物。通过比对日志中 CaptureResult 的状态机变化,可以极大地缩短 Bug 排查周期。



评论