如何在绑定到 CameraX 分析器的执行器中添加延迟?

How to add a delay inside the Executor bound to CameraX's analyzer?

在我覆盖的 analyze() 中,我需要在执行 IO 操作之前添加某种限制。如果没有油门,这个操作会在每次调用 analyze() 时立即执行,并且它实际上很快完成,但显然调用太快了一段时间后相机预览永远冻结(应用程序仍然 运行 因为 Logcat 不断显示新消息)。

我目前正在调查它是否与我的代码有关,例如忘记调用 imageProxy.close()。到目前为止,一切似乎都很好,恐怕执行 IO 操作的设备引发了太多中断,CPU 无法处理,或者类似的事情。

我已经尝试过旧的 Thread.sleep() 但显然它会阻塞主线程并冻结 UI;我看过一些 Handler#postDelayed() 的例子,但我不认为它符合我的要求;我试过在开始时用 delay() 将 IO 调用包装在一个协程中,但我又一次认为它没有达到我想要的效果。基本上我想在 Executor 线程本身上调用某种形式的 sleep(),从它执行的代码中。

after a while the camera preview freezes for eternity

我见过这个问题多次出现,通常是因为 Analyzer 没有关闭图像。即使未使用图像分析用例,您是否也看到了问题?

I've tried the good old Thread.sleep() but obviously it blocks the main thread and freezes the UI

这是为什么?如果您在 Analyzer.analyze() 中添加对 Thread.sleep() 的调用,则情况不应如此,因为它会阻塞您在调用 ImageAnalysis.setAnalyzer() 时提供的 Executor 的线程,不应绑定到主线程。

减少分析次数的一个选项是将图像放在 Analyzer 中,如下所示:

private static final int ANALYSIS_DELAY_MS = 1_000;
private static final int INVALID_TIME = -1;
private long lastAnalysisTime = INVALID_TIME;

public void analyze (ImageProxy image) {
  final long now = SystemClock.uptimeMillis();

  // Drop frame if an image has been analyzed less than ANALYSIS_DELAY_MS ms ago
  if (lastAnalysisTime != INVALID_TIME && (now - lastAnalysisTime < ANALYSIS_DELAY_MS)) {
    image.close();
  }

  lastAnalysisTime = now;
  
  // Analyze image
  image.close();
}

还有一种方法,我在本地项目中就是这样做的。因此,在我的图像分析器中,我使用 Handler#PostDelayed 重新绑定相机,这会在预览时出现一个小黑屏,但它不会那么快地处理下一张图像。

我的用例是我要连续扫描条码,但是扫描速度太快,一直在扫描一个代码很多次。所以,我只需要 100 毫秒的等待时间。所以这对我有用。

try {
    cameraProvider.unbindAll()
    Handler(Looper.getMainLooper()).postDelayed({
         cameraProvider.bindToLifecycle(
             this, CameraSelector.DEFAULT_BACK_CAMERA, useCaseGroup.build())
    }, 100)
}
catch(exc: Exception) {
     Log.e(TAG, "Use case binding failed", exc)
}