Job 🔗
A failure of any child immediately causes the Job
to fail and cancels the rest of its children.
val scope = CoroutineScope(Dispatchers.Main + Job())
scope.launch { // the first child
throw Exception()
}
scope.launch { // the second child
// canceled by the failure of the first child
}
SupervisorJob 🔗
A failure of a child does not cause the SupervisorJob
to fail and does not affect its other children.
val scope = CoroutineScope(Dispatchers.Main + SupervisorJob())
scope.launch { // the first child
throw Exception()
}
scope.launch { // the second child
// NOT canceled by the failure of the first child
}
coroutineScope 🔗
A failure of a scope cancels all its children.
coroutineScope {
val child = async {
// canceled by the failure of the scope
}
throw Exception()
}
A failure of any child causes the scope to fail and the rest of the children are canceled.
coroutineScope {
val child1 = async {
throw Exception()
}
val child2 = async {
// canceled by the failure of the first child
}
child1.await()
}
Since the failure of a child causes the scope itself to fail, using try-catch on a child will NOT work.
coroutineScope {
try {
val child = async { throw Exception() }.await()
} catch (e: Exception) {
// coroutineScope rethrows the exception
}
}
Exception thrown by a child is rethrown by the coroutineScope
and can be handled from the outer scope.
suspend fun someFunction() = coroutineScope {
val child = async { throw Exception() }.await()
}
val scope = CoroutineScope(Dispatchers.Main + Job())
scope.launch {
try {
someFunction()
} catch (e: Exception) {
// exception successfully caught
}
}
supervisorScope 🔗
A failure of a scope cancels all its children.
supervisorScope {
val child = async {
// canceled by the failure of the scope
}
throw Exception()
}
A failure of a child does not cause the scope to fail and does not affect its other children.
supervisorScope {
val child1 = async {
throw Exception()
}
val child2 = async {
// NOT canceled by the failure of the first child
}
try {
child1.await()
} catch (e: Exception) {
// exception successfully caught
}
}
Exception thrown by the supervisorScope
can be handled from the outer scope.
suspend fun someFunction() = supervisorScope {
val child = async { throw Exception() }.await()
}
val scope = CoroutineScope(Dispatchers.Main + Job())
scope.launch {
try {
someFunction()
} catch (e: Exception) {
// exception successfully caught
}
}
suspendCoroutine 🔗
Suspends currently running coroutine. Provided continuation
has two functions: resume
and resumeWithException
,
calling either function will cause suspendCoroutine
to resume immediately. Typically used to convert callback-based
APIs to suspend functions.
suspend fun <T> Call<T>.await(): T {
return suspendCoroutine { continuation ->
this.enqueue(object : Callback<T> {
override fun onResponse(call: Call<T>, response: Response<T>) {
continuation.resume(response.body()!!)
}
override fun onFailure(call: Call<T>, t: Throwable) {
continuation.resumeWithException(t)
}
})
}
}
suspendCancellableCoroutine 🔗
Works similarly to suspendCoroutine
but supports cancellation.
suspend fun <T> Call<T>.await(): T {
return suspendCancellableCoroutine { continuation ->
this.enqueue(object : Callback<T> {
override fun onResponse(call: Call<T>, response: Response<T>) {
continuation.resume(response.body()!!)
}
override fun onFailure(call: Call<T>, t: Throwable) {
continuation.resumeWithException(t)
}
})
continuation.invokeOnCancellation {
this.cancel()
}
}
}
Channel 🔗
Hot stream: The data is being produced regardless of the presence of subscriber.
Flow 🔗
Cold stream