In Android, I usually see some code snippet of suspend functions like this:
viewModelScope.launch { //implemented by Person1
A()
}
//implemented by Person2
suspend fun A() {
B()
}
//implemented by Person3
suspend fun B() {
C()
}
//implemented by Person4
suspend fun C() {
doSomething()
}
If Person3 may write like below to let C() running on the different thread
suspend fun B() {
withContext(Dispatchers.IO) {
C()
}
}
What is the Person2 who is responsible for A() also think since he is calling suspend function B, so he need to let B running on a thread.
This may create multiple threads which is not necessary, so how to let the Person1 and Person2 know the suspend function he calls is already running on the different thread.
Let's assume
doSomethingaccesses the file system. It's then the responsibility of that function to move those parts on the IO dispatcher. The function could look like this:The caller of
doSomething, functionC, does not need to know about the file system access and which dispatcher the function is executed on. It can simply calldoSomething()and everything is fine.Now, let's assume
Bdecides to callClike this:The current coroutine will be moved from the current thread to a thread of the IO dispatcher and
Cis called.Cthen callsdoSomethingand that function now also executeswithContext(Dispatchers.IO). But the coroutine already is on that dispatcher, so no additional thread switches happen. Then, the file system access occurs. On a thread of the IO dispatcher, asBaswell asdoSomethingmade sure of.withContextdoesn't create a new coroutine that would occupy a new thread. Instead, the current coroutine is configured in a way that it runs on the appropriate thread - but if it already is running on the correct thread, nothing changes, no new threads are occupied. You can callwithContext(Dispatchers.IO)any number of times, only the first one actually has an effect.This is different from launching a new coroutine with
launchorasync. That may very well lead to the dispatcher creating a new thread (or reusing one from the thread pool). But that's what suspend functions are for: When you already are in a suspend function, no new coroutine is needed to call the next suspend function. No new threads are involved.To conclude, it is not necessary that
Bswitches to the IO dispatcher, but it also does no harm. But the documentation ofdoSomethingandCcould confirm that the internals make sure the file system access is moved to the IO dispatcher. That wayBwouldn't have to guess if everything is handled correctly and ifBshould, just to make sure, move the current coroutine to the IO dispatcher itself.