In the context of Android, What is the difference between a dispatcher vs main thread.
As per my understanding referring the documentation,
It is backed by a shared pool of threads on JVM. By default, the maximal level of parallelism used by this dispatcher is equal to the number of CPU cores, but is at least two. Level of parallelism X guarantees that no more than X tasks can be executed in this dispatcher in parallel.
Will it spawn a new thread or there will be as per the log name DefaultDispatcher-worker-1
a worker that will communicate with the pool of threads other than the main to handle a block of co-routine or worker itself is a Co-routine?
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val timeInMillis = measureTimeMillis {
GlobalScope.launch(Dispatchers.Default) {
Log.d(TAG, "Starting coroutine in thread ${Thread.currentThread().name}")
val answer = doNetworkCall()
withContext(Dispatchers.Main) {
Log.d(TAG, "Setting text in thread ${Thread.currentThread().name}")
}
}
}
Log.d(TAG, "(The operation took $timeInMillis ms)")
}
CodePudding user response:
A Dispatcher is essentially a thread pool. When you use launch(Dispatchers.Default)
, the Thread used to run the code in the coroutine will be obtained from Dispatchers.Default
. Each time there is a suspend function call in the coroutine, when the coroutine resumes after that call, it might be resuming on a different Thread instance coming from the same Dispatchers.Default
thread pool.
"DefaultDispatcher-worker-1"
is the name of a literal Thread
instance that came from the Dispatcher.Default
's pool.
withContext
is itself a suspend function call, so any code after the withContext
block will also be resumed on some thread from Dispatchers.Default
. (There is none in your example).
The code inside withContext(Dispatchers.Main)
will be run on a thread from Dispatchers.Main
.
Dispatchers.Main
is a special Dispatcher that has only one thread, and that thread is the same Main Thread used by the OS.
You should rarely ever need to use GlobalScope
and it is discouraged because it doesn't allow easy management of coroutine lifecycles. If you use lifecycleScope
instead, your coroutines will be automatically cancelled when the associated Activity or Fragment is shut down. This is usually what you want, because an Activity or Fragment shouldn't be continuing to do work after it's gone.
Usually on Android, most coroutines should be launched from lifecycleScope
or viewModelScope
and should not need to have a Dispatcher specified since these scopes by default use Dispatchers.Main
which is usually what you want. (Actually they use a different dispatcher called Dispatchers.Main.immediate
which also uses the main thread but also can run the first part of a coroutine immediately without deferring to the next frame of the main thread loop. Not a distinction you need to worry about.) You can wrap the pieces of your coroutine that need other dispatchers in withContext
. You don't need to do this if you are only calling suspend functions. By convention it is up to suspend functions to internally delegate to a specific Dispatcher if they need to.
An exception to the above paragraph might be if you're launching a coroutine in viewModelScope
that does some blocking work and never touches anything that is main-thread-only. Then you can skip withContext
and specify a dispatcher explicitly with launch
.