cancel
Cancels this scope, including its job and all its children with an optional cancellation cause.
A cause can be used to specify an error message or to provide other details on a cancellation reason for debugging purposes.
Throws IllegalStateException if the scope does not have a job in it.
This function is shorthand for coroutineContext[Job]?.cancel(cause) ?: throw IllegalStateException().
Usage
Cancelling non-lexically scoped coroutines
The primary purpose of this function is to cancel a manually created CoroutineScope when its lifecycle ends.
class ThingWithItsOwnLifetime(scope: CoroutineScope? = null): AutoCloseable {
private val scope = scope ?: CoroutineScope(
SupervisorJob() + Dispatchers.Main +
CoroutineExceptionHandler { _, e ->
// handle uncaught coroutine exceptions appropriately
}
)
override fun close() {
// the computations should all stop running
scope.cancel()
}Failing to cancel the scope when it is no longer in active use will lead to resource leaks and can also potentially crash the program if some object used by the child coroutines becomes destroyed.
Cancelling lexical CoroutineScope
For lexically scoped coroutines, such as those created with coroutineScope or withContext, canceling the scope explicitly is very rarely required.
If no child coroutines were started, but it became obvious that the computation won't be needed, the scope can simply be exited:
coroutineScope {
if (computationNotNeeded) return@coroutineScope
// Start some child coroutines
// ...
}Also, if the caller is cancelled, the scope will be cancelled as well, so there is no need to cancel it explicitly.
cancel may be useful in cases when one child coroutine detects that the whole parent scope is no longer needed and wants to cancel it:
coroutineScope {
val parentScope = this
launch {
val userRequest = getUserRequest()
if (userRequest == TERMINATE) {
parentScope.cancel()
}
// Do something with the request
// ...
}
// Start other child coroutines...
}Pitfalls
Cancelling oneself
Cancelling a scope does not mean the computation finishes immediately, as coroutine cancellation is cooperative. Only the next suspension point will observe the cancellation. For example:
try {
coroutineScope {
cancel()
println("Will be printed anyway!")
}
} catch (e: CancellationException) {
println(
"The scope was cancelled " +
"(the parent coroutine is still active: ${currentCoroutineContext().isActive})"
)
throw e
}will output
Will be printed anyway!
The scope was cancelled (the parent coroutine is still active: true)Use return to immediately return from the scope after cancelling it:
coroutineScope {
cancel()
return@coroutineScope
println("Will not be printed")
}Cancels this scope with a CancellationException with the given message and cause.
Shorthand for cancel(CancellationException(message, cause)).
Cancels Job of this context with an optional cancellation cause. See Job.cancel for details.
Cancels current job, including all its children with a specified diagnostic error message. A cause can be specified to provide additional details on a cancellation reason for debugging purposes.