Unintuitive dispatching behavior in some rare cases with Android's Dispatchers.Main.immediate
#3963
Closed
Description
See #3924 (comment)
This code produces 1
, 2
, 3
:
@Test
fun foo() {
GlobalScope.launch(Dispatchers.IO) {
withContext(Dispatchers.Main.immediate) {
println("1")
launch(Dispatchers.Main) {
println("2")
}
withContext(Dispatchers.Main) {
println("3")
}
}
}
}
This code, however, produces 1
, 3
, 2
:
@Test
fun foo() {
GlobalScope.launch(Dispatchers.Main) { // <-- note the different dispatcher
withContext(Dispatchers.Main.immediate) {
println("1")
launch(Dispatchers.Main) {
println("2")
}
withContext(Dispatchers.Main) {
println("3")
}
}
}
}
This behavior may be surprising. For example, consider this pseudo-code:
fun updateUi() = scope.launch(Dispatchers.Main) { }
suspend fun readUiElement(): Int = withContext(Dispatchers.Main) { 1 }
fun update() = viewModelScope.launch {
updateUi()
cache = readUiElement()
}
Depending on whether update
is called from the main thread, the block in updateUi
will happen either earlier or later than readUiElement
, even though visually, it seems like updateUi
should happen earlier.
Notably, all the other implementations of Dispatchers.Main
that we provide don't suffer from the same problem but instead consistently output 1
, 2
, 3
in both scenarios.