MainScope

Creates a CoroutineScope for scheduling UI updates.

Usage example:

class MyAndroidActivity: Activity() {
// be careful not to write `get() =` here by accident!
private val scope = MainScope() + CoroutineExceptionHandler { _, e ->
log("Unhandled error in coroutine: $e")
}

fun updateProgressBar(newValue: Int) = scope.launch {
// this coroutine will run on the main thread
// ...
}

override fun onDestroy() {
super.onDestroy()
scope.cancel()
}
}

The new scope has Dispatchers.Main in its context, meaning that all coroutines launched in it will run on the main thread. It also has a SupervisorJob in its context, meaning that if one of the child coroutines fails, the other coroutines will not be affected. A CoroutineExceptionHandler is not installed.

If you want to append additional elements to the main scope, use the CoroutineScope.plus operator: val scope = MainScope() + CoroutineName("MyActivity").

Pitfall: this scope does not include a CoroutineExceptionHandler and creates a job without a parent. Together, this means that if a child coroutine created with launch fails with an exception, the failure will be reported in a platform-specific manner (e.g., a crash on Android). Always supply a CoroutineExceptionHandler to MainScope using the plus operator if there is a chance that a child coroutine may fail with an exception, or use async instead of launch to have the consumer of the result handle the exception.

Pitfall: there is no memoization of the CoroutineScope instance in this function. Every call to this function creates a new instance of MainScope, with an unrelated SupervisorJob. For example, writing MainScope().cancel() is meaningless, because the only job that will be cancelled is the one created in that specific MainScope() call.