// This is pseudo-code for purposes of understanding !!NOT TO BE USED AS IS!!suspend fun <T> coroutineScope(block: suspend CoroutineScope.() -> T): T { // Get the current coroutine context val currentContext = coroutineContext // Create a new Job that's a child of the current job val scopeJob = Job(parent = currentContext[Job]) // Create a new scope with the new job val scope = CoroutineScope(currentContext + scopeJob) try { // Execute the block and get result val result = block(scope) // This conceptually "waits" for all children to complete // (In reality this would need to be done differently) scopeJob.complete() // Signal no more children will be added scopeJob.join() // Wait for existing children return result } catch (e: Exception) { // Cancel all children on any exception scopeJob.cancelChildren() throw e }}
Another function that behaves a lot like coroutineScope
is withTimeout. It also creates a scope and returns a value.
Actually, withTimeout with a very big timeout behaves just like
coroutineScope. The difference is that withTimeout additionally sets
a time limit for its body execution. If it takes too long, it cancels
this body and throws TimeoutCancellationException (a subtype of
CancellationException).
Beware that withTimeout throws TimeoutCancellationException,
which is a subtype of CancellationException (the same exception
that is thrown when a coroutine is cancelled). So, when this
exception is thrown in a coroutine builder, it only cancels it and
does not affect its parent (as explained in the previous chapter). - kotlin-coroutines-deep-dive
The withContext function is similar to coroutineScope, but it
additionally allows some changes to be made to the scope. The
CoroutineContext provided as an argument to this function overrides the
context from the parent scope (the same way as in coroutine
builders). This means that withContext(EmptyCoroutineContext)
and coroutineScope() behave in exactly the same way.
The function withContext is often used to set a different coroutine
scope for part of our code. Usually, you should use it together with
Dispatcher. - kotlin-coroutines-deep-dive
The supervisorScope function also behaves a lot like coroutineScope:
it creates a CoroutineScope that inherits from the outer scope and
calls the specified suspend block in it. The difference is that it
overrides the context’s Job with Supervisor-Job, so it is not cancelled
when a child raises an exception.
supervisorScope is mainly used in functions that start multiple independent tasks. - kotlin-coroutines-deep-dive
Highlight
Does NOT cancel when child raises an exception.
Does NOT cancel children when child raises an exception.
Waits for ALL children, even failing ones, even after some have failed and threw.