提问人:mo5ch 提问时间:3/11/2023 更新时间:3/18/2023 访问量:218
Android 与 ViewModel 和 CameraX 的线程间通信最佳实践?
Android inter thread communication best practices with ViewModel and CameraX?
问:
我有以下情况(查看下面的代码):
- 从 CameraX 用例的循环中获取
ImageProxy
ImageAnalyzer
- 分析图像(大约需要 20 毫秒)并返回一些信息,
close()
ImageProxy
- 通过 AsyncTask 分析提取的信息(大约需要 500 到 3000 毫秒)
- 如果成功,则显示结果
我有一些片段,这取决于任务 1 的成功程度。和 2.是(特别是 PreviewView 片段和一些结果页面)。目前,他们收到 .当图像被任一任务 1 分析时。或 2.我用 .这当然不理想,因为我还需要在我的任务中监听该状态,以防上一个图像产生了我可以显示给用户的结果。ViewModel
viewModel.analyzerState.postValue(<newState>)
我现在的问题如下:
当结果准备就绪时,任务 1。或 2.可能仍在运行并产生另一个结果,然后触发 UI 更新两次。我不想这样,但我仍然希望任务并行运行,以防前一个任务失败(这种情况经常发生)。当我确定我有结果时,我希望取消任务(我已经调用了 AsyncTask,但这不起作用)。我认为我的问题是使用 作为线程间通信的消息传递工具,因为我在任务 1 中设置了状态。以及任务 2 中。并在循环中聆听它。cancel()
ViewModel
我能找到的唯一信息是使用 Kotlin 协程,这显然是为使用 而制作的,但我使用的是 Java。ViewModel
解决此类问题的标准方法是什么?如何在各种线程和片段之间安全地进行通信?
法典:
void analyzeImage(ImageProxy imageProxy) { // loop called by CameraX
if (viewModel.analyzerState.getValue() == 'done') {
imageProxy.close();
return;
}
viewModel.analyzerState.postValue('extracting');
Data data = extractData(imageProxy);
imageProxy.close();
if (data.isValid()) {
viewModel.analyzerState.postValue('analyzing');
new DataAnalyzeTask.execute(data);
} else {
viewModel.analyzerState.postValue('idle');
}
}
// UI listens with
viewModel.analyzerState.observe(getViewLifecycleOwner(), state -> { /*...*/ } );
答:
我花了一些时间和很多变化,但现在我有一个适合我目的的解决方案。因此,我没有使用 和 for 通信,而是实现了我自己的类,它基本上只是一个带有一些回调的类。这些回调允许我与 UI 进行通信。然后,UI 使用 (在主线程上) 传播数据更改。为了确保我在主线程上,我在主线程处理程序中执行回调:AsyncTask
ViewModel
Task
Runnable
ViewModel
Handler mainThreadHandler = HandlerCompat.createAsync(Looper.getMainLooper());
// in Task class:
mainThreadHandler.post(new Runnable() {
@Override
public void run() {
callback.onSomethingHappend(result);
}
});
我的自定义 s 通过以下命令在线程池中执行:Task
ExecutorService
ExecutorService executor = Executors.newFixedThreadPool(4); // should be called only once when the application launches
executor.execute(new Task(data, callback));
我认为可能有一个更简单的解决方案(因为我或多或少地用我的和类重新实现了这些),但我现在不想将 Guava 添加到我的项目中。ListenableFuture
Task
TaskCallback
为了确保我可以取消我的任务,一旦我得到一些结果,我就使用并将该值设置为 false:AtomicBoolean
atomicBoolean.compareAndSet(/*expectedValue=*/false, /*newValue=*/true);
以下是一些有用的资源:
https://developer.android.com/guide/background/asynchronous/java-threads https://developer.android.com/guide/background/asynchronous/listenablefuture
评论