Coroutine Scope

CoroutineScopeinterface encapsulates theCoroutineContext.- Coroutine builders like
launch{},async{}are extensions on the coroutine scope.
- Coroutine builders like
Coroutine library provides a function called
CoroutineScopefor initialization of theCoroutineScope.It is generally not recommended to directly access the
coroutineContextproperty of aCoroutineScope- such as
coroutineContext[CoroutineDispatcher], except for accessing theJobinstance for advanced use cases.
- such as
CoroutineScopealways keep an instance of aJobto manage structured concurrency.coroutineContextandcurrentCoroutineContext()Both returns the
coroutineContextinstance.currentCoroutineContext()added as an alias to avoid name clash withCoroutineScope.coroutineContextin a receiver position.
CoroutineScope extension functions
plus(context: CoroutineContext):
- To override the existing context element in current scope.
ensureActive():
Ensures that current scope is active.
If the job is no longer active, throws
CancellationException.
cancel(cause: CancellationException? = null):
Cancels the current scope, including its job and all its children with an optional cancellation cause.
A cancellation cause can be used to specify an error message or to provide other details on a cancellation reason for debugging purposes.
Throws
IllegalStateExceptionif the scope does not have a job in it.
Example: CoroutineScope usage
suspend fun main() {
val context = EmptyCoroutineContext + Dispatchers.Default
val scope = CoroutineScope(context)
scope.launch {
println("Coroutine launch builder is Coroutine scope's extension function")
}.join()
}
CoroutineScope Interface
public interface CoroutineScope {
public val coroutineContext: CoroutineContext
}
CoroutineScope internal initialization implementation
internal class ContextScope(context: CoroutineContext) : CoroutineScope {
override val coroutineContext: CoroutineContext = context
override fun toString(): String = "CoroutineScope(coroutineContext=$coroutineContext)"
}
CoroutineScope Function
@Suppress("FunctionName")
public fun CoroutineScope(context: CoroutineContext): CoroutineScope =
ContextScope(if (context[Job] != null) context else context + Job())
CoroutineScope(), MainScope(), GlobalScope object and coroutineScope{}
CoroutineScope() function:
- It bounds to a Job when creates coroutine scope with a specified context.
MainScope() function:
Runs on main thread as it sets
Dispatchers.Maindispatcher internally.It is bound with SupervisorJob.
On Android, MainScope() is safer instead GlobalScope object to create a scope.
GlobalScope object:
Uses
EmptyCoroutineContext.It is not bound to any job.
coroutineScope{} suspend function:
Creates a
CoroutineScopeand it's a suspend function.Calls the specified suspend block with this scope.
This scope inherits its
coroutineContextfrom the outer scope, but overrides the context's Job.This function is designed for parallel decomposition of work.
When any child coroutine in this scope fails, this scope fails and all the rest of the children are cancelled.
SupervisorJobcan be used to handle the bi-directional error propagation.
This function returns as soon as the given block and all its children coroutines are completed.
CoroutineScope Function
@Suppress("FunctionName")
public fun CoroutineScope(context: CoroutineContext): CoroutineScope =
ContextScope(if (context[Job] != null) context else context + Job())
Main scope function implementation
@Suppress("FunctionName")
public fun MainScope(): CoroutineScope = ContextScope(SupervisorJob() + Dispatchers.Main)
GlobalScope object implementation
public object GlobalScope : CoroutineScope {
override val coroutineContext: CoroutineContext
get() = EmptyCoroutineContext
}
coroutineScope{} suspend function
public suspend fun <R> coroutineScope(block: suspend CoroutineScope.() -> R): R {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return suspendCoroutineUninterceptedOrReturn { uCont ->
val coroutine = ScopeCoroutine(uCont.context, uCont)
coroutine.startUndispatchedOrReturn(coroutine, block)
}
}
Coroutine Scope Cancellation
public fun CoroutineScope.cancel(cause: CancellationException? = null) {
val job = coroutineContext[Job]
?: error("Scope cannot be cancelled because it does not have a job: $this")
job.cancel(cause)
}
//OR
public fun CoroutineScope.cancel(message: String, cause: Throwable? = null): Unit =
cancel(CancellationException(message, cause))
Happy coding... 😊



