My guess is that it is similar to how JavaScript manages blocking operations with the event loop
Yes, this is correct, the event loop is essential to making coroutines work. Basically, when you write this:
uiScope.launch {
delay(1000)
println("A second has passed")
}
it compiles into code that has the same effect as this:
Handler(Looper.mainLooper()).postDelayed(1000) { println("A second has passed") }
The main concept is the continuation, an object that implements a state machine that corresponds to the sequential code you wrote in a suspendable function. When you call delay
or any other suspendable function, the continuation's entry-point method returns a special COROUTINE_SUSPENDED
value. Later on, when some outside code comes up with the return value of the suspendable function, it must call continuation.resume(result)
. This call will be intercepted by the dispatcher in charge, which will post this call as an event on the GUI event loop. When the event handler is dequeued and executed, you are back inside the state machine which figures out where to resume the execution.
You can review this answer for a more fleshed-out example of using the Continuation
API.
I can run blocking operations with this scope and the UI does not freeze at all.
? Please provide an example? – Hollingtondelay(1000)
. Shouldn't this cause an ANR screen to appear if I am doing this on the UI thread? – Mills