0

我正在测试一个实例AsyncTaskonPostExecute调用。由于我正在调用关于 UI 线程正在执行的调用的任何问题。setValueLiveDatasetValueonPostExecute

然而,在 Robolectric 单元测试中运行它,我得到:java.lang.IllegalStateException: Cannot invoke setValue on a background thread

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

var cf = new CompletableFuture<T>();
livedata.observe(ctrl.get(), it -> cf.complete(it));
// ... perform the AsyncTask that will update livedata in onPostExecute
await().until(() -> {
    flushBackgroundThreadScheduler()
    flushForegroundThreadScheduler()
    cf.isDone
});

这是IllegalStateException: Cannot invoke setValue on a background threadflushForegroundThreadScheduler()打电话!!!!

为什么我得到这个异常?我怎样才能onPostExecute像在 UI 线程中那样执行?

更新

记录线程似乎两者flushBackgroundThreadScheduler()都是flushForegroundThreadScheduler()内联同步执行的。我可以观察到:

LiveData created on thread 763324286
Background thread 1519527121
LiveData updated on thread 1519527121

由于传递给的 lambdaawait.until在另一个线程上运行,因此两者flushBackgroundThreadScheduler()flushForegroundThreadScheduler()都在该线程 1519527121 上执行。

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

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

1 回答 1

0

我们必须考虑以下因素:

  1. Robolectric:flushForegroundThreadScheduler()内联同步执行。
  2. 等待性:await.until(<Callable>)在后台线程中评估直到条件。

从这两个语句中,我们观察到flushForegroundThreadScheduler()Callable传递到调用会await.until(<Callable>)导致在后台线程中调用调度的前台任务,这回答了第一个 OP 问题:为什么我得到这个异常?

回答第二个OP问题:

我怎样才能onPostExecute像在 UI 线程中那样执行?

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

await().pollInSameThread().until(() -> {
    flushBackgroundThreadScheduler()
    flushForegroundThreadScheduler()
    cf.isDone
});
于 2019-11-06T11:40:03.680 回答