From the Antonio Leiva article about coroutines:
The coroutine context is a set of rules and configurations that define
how the coroutine will be executed
withContext
is a function that allows you to easily change the context
of a suspending function, in order to be sure that that function is executed in a particular thread (E.g. Thread from IO pool). To do so you can force a suspending function to execute its body within a particular thread pool, for example:
suspend fun getAuthenticationStatus(): AuthenticationStatus = withContext(Dispatchers.IO) {
when (val result = repository.getAuthenticationStatus()) {
is Result.Success -> result.data
is Result.Error -> AuthenticationStatus.Unauthorized
}
}
This way, even if you're calling this suspending function from a UI scope (MainScope), you are 100% sure that the suspending function is executed in a worker thread and you can update the UI with the returned result in the main thread, such as:
MainScope().launch {
userIdentityVM.getAuthenticationStatus().run {
when (this) {
is AuthenticationStatus.Authenticated -> {
// do something
}
is AuthenticationStatus.Unauthorized -> {
// do something else
}
}
}
}
To sum up, by using withContext
you can make your suspending function "Main Safe".
The difference between scope
and context
is basically the intended purpose.
To launch a coroutine you normally use launch
coroutine builder, defined as an extension function on CoroutineScope
.
fun CoroutineScope.launch(
context: CoroutineContext = EmptyCoroutineContext,
// ...
): Job
The context specified as parameter on the coroutine scope is merged to coroutine scope by plus operator and takes precedence on the "default" context specified by coroutine scope. This way you can execute the code in a "parent" context. To go deep I suggest you this article by Roman Elizarov (Team Lead for Kotlin libraries @JetBrains).