Android Robolectric无法在后台线程上调用setValue

Android Robolectric无法在后台线程上调用setValue,android,android-asynctask,robolectric,android-livedata,androidx-test,Android,Android Asynctask,Robolectric,Android Livedata,Androidx Test,我正在测试一个AsyncTask,它onPostExecute调用setValue一个LiveData实例。由于我正在从onPostExecute调用setValue,因此预期UI线程执行的调用不会出现任何问题 然而,在一个Robolectric单元测试中运行它,我得到:java.lang.IllegalStateException:无法在后台线程上调用setValue 为了使此单元测试等待后台和前台任务完成,我通过以下方式利用等待工具: var cf=newcompletablefuture(

我正在测试一个
AsyncTask
,它
onPostExecute
调用
setValue
一个
LiveData
实例。由于我正在从
onPostExecute
调用
setValue
,因此预期UI线程执行的调用不会出现任何问题

然而,在一个Robolectric单元测试中运行它,我得到:
java.lang.IllegalStateException:无法在后台线程上调用setValue

为了使此单元测试等待后台和前台任务完成,我通过以下方式利用等待工具:

var cf=newcompletablefuture();
livedata.observe(ctrl.get(),it->cf.complete(it));
// ... 执行将在onPostExecute中更新livedata的异步任务
等待()。直到(()->{
flushBackgroundThreadScheduler()
flushForegroundThreadScheduler()
cf.isDone
});
这正在抛出一个
非法状态异常:无法在
flushForegroundThreadScheduler()
调用上的后台线程上调用setValue

为什么我会得到这个例外?我怎样才能像在UI线程中一样执行
onPostExecute

更新

日志线程似乎
flushBackgroundThreadScheduler()
flushForegroundThreadScheduler()
都是以内联方式同步执行的。我可以观察到:

LiveData created on thread 763324286
Background thread 1519527121
LiveData updated on thread 1519527121
由于lambda传递给
等待。直到
在另一个线程上运行,那么
flushBackgroundThreadScheduler()
flushForegroundThreadScheduler()
都会在该线程1519527121上执行

因此,我可以通过在与UI线程对应的测试线程中运行以下变通方法来解决我的问题。然而,我需要
Thread.sleep()
才能成功,我不喜欢它

Thread.sleep(1000)
flushBackgroundThreadScheduler()
flushForegroundThreadScheduler()
cf.isDone

我们必须考虑以下因素:

  • Robolectric:
    flushForegroundThreadScheduler()
    以内联方式同步执行
  • 等待性:
    await.until()
    在后台线程中计算until条件
  • 从这两条语句中,我们观察到从传递给
    await.until()
    Callable
    调用
    flushForegroundThreadScheduler()
    会导致在后台线程中调用调度的前台任务,这回答了第一个OP问题:为什么我会出现此异常

    回答第二个问题:

    如何像在UI线程中一样执行
    onPostExecute

    由于Robolectric为UI操作和测试代码共享一个线程,因此我们必须使用
    pollInSameThread
    来指示应该在与启动等待性的测试用例相同的线程上评估until条件。OP示例代码应固定为:

    wait().pollInSameThread().until(()->{
    flushBackgroundThreadScheduler()
    flushForegroundThreadScheduler()
    cf.isDone
    });
    
    flushForegroundThreadScheduler中有什么?@GensaGames我不明白你的问题
    flushForegroundThreadScheduler
    是Robolectric library提供的一种方法。我认为您正在寻找的答案如下: