I am testing an AsyncTask
that onPostExecute
calls setValue
of a LiveData
instance. Since I am invoking setValue
from onPostExecute
no issues were expected regarding the invocation being done by the UI thread.
Yet running this in a Robolectric unit test I got: java.lang.IllegalStateException: Cannot invoke setValue on a background thread
To make this unit test wait for background and foreground tasks completion I take advantage of awaitility tool in the following way:
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
});
This is throwing an IllegalStateException: Cannot invoke setValue on a background thread
on flushForegroundThreadScheduler()
call!!!!
Why I am getting this exception? And how can I have the onPostExecute
being performed like in the UI thread?
UPDATE
Logging threads it seems that both flushBackgroundThreadScheduler()
and flushForegroundThreadScheduler()
are executed synchronously inline. I can observe:
LiveData created on thread 763324286
Background thread 1519527121
LiveData updated on thread 1519527121
Since the lambda passed to await.until
runs on another thread, then both flushBackgroundThreadScheduler()
and flushForegroundThreadScheduler()
are performed on that thread 1519527121.
Thus, I can solve my problem with the following workaround running in the test thread corresponding to UI Thread. Yet, I need that Thread.sleep()
to succeed and I don't like it.
Thread.sleep(1000)
flushBackgroundThreadScheduler()
flushForegroundThreadScheduler()
cf.isDone