Reputation: 303
code:
viewModelScope.launch(CoroutineExceptionHandler { _, _ ->
Log.e("TAG", "task 1")
}) {
try {
Log.e("TAG", "task 1 start")
delay(3000)
Log.e("TAG", "task 1 finished")
} catch (ex: Exception) {
Log.e("TAG", "task 1 cancelled " + ex)
}
}
launch = viewModelScope.launch(CoroutineExceptionHandler { _, _ ->
Log.e("TAG", "handler 1" + myJob?.isCancelled)
}) {
myJob = SupervisorJob()
launch(myJob!! + CoroutineExceptionHandler { _, _ ->
Log.e("TAG", "handler 2 " + myJob?.isCancelled)
}) {
delay(300)
launch {
try {
Log.e("TAG", "task 2 start")
delay(5000)
Log.e("TAG", "task 2 finished")
} catch (ex: Exception) {
Log.e("TAG", "task 2 ex " + ex)
}
}
launch {
delay(2000)
throw Exception()
}
}
launch {
try {
Log.e("TAG", "task 3 start")
delay(3000)
Log.e("TAG", "task 3 finished")
} catch (ex: Exception) {
Log.e("TAG", "task 3 ex " + ex)
}
}
}
output:
2020-01-06 09:47:56.462 7159-7159/? E/TAG: task 1 start
2020-01-06 09:47:56.496 7159-7159/? E/TAG: task 3 start
2020-01-06 09:47:56.798 7159-7159/com.mvvm.template.debug E/TAG: task 2 start
2020-01-06 09:47:58.822 7159-7159/com.mvvm.template.debug E/TAG: task 2 ex kotlinx.coroutines.JobCancellationException: Parent job is Cancelling; job=StandaloneCoroutine{Cancelling}@81a8e39
2020-01-06 09:47:58.827 7159-7159/com.mvvm.template.debug E/TAG: handler 2 false
2020-01-06 09:47:59.464 7159-7159/com.mvvm.template.debug E/TAG: task 1 finished
2020-01-06 09:47:59.499 7159-7159/com.mvvm.template.debug E/TAG: task 3 finished
my issue:
I’m having an issue to understand why task 2 is canceled when it’s a child of SupervisorJob and the exception happened on an other child.
The documentation state:
A failure or cancellation of a child does not cause the supervisor job to fail and does not affect its other children, so a supervisor can implement a custom policy for handling failures of its children. Am i missing something or what ? any help would be appreciated.
Upvotes: 3
Views: 1821
Reputation: 40878
I’m having an issue to understand why task 2 is canceled when it’s a child of SupervisorJob and the exception happened on an other child.
Here this is not a direct answer to the question as it's already answered well by the accepted answer as the parent is not the SupervisorJob
But in order to achieve the intended behavior of making task2 independent of the sibling jobs:
You've to use SupervisorJob
by either:
SupervisorJob
the parent of each task that you want to be independent of one another:In your example:
val myJob = SupervisorJob()
val launch = viewModelScope.launch(CoroutineExceptionHandler { _, _ ->
Log.e("TAG", "handler 1" + myJob.isCancelled)
}) {
launch(CoroutineExceptionHandler { _, _ ->
Log.e("TAG", "handler 2 " + myJob.isCancelled)
}) {
delay(300)
launch(myJob) { // <<<<<<<<< myJob is the parent
try {
Log.e("TAG", "task 2 start")
delay(5000)
Log.e("TAG", "task 2 finished")
} catch (ex: Exception) {
Log.e("TAG", "task 2 ex $ex")
}
}
launch(myJob) { // <<<<<<<<< myJob is the parent
delay(2000)
throw Exception()
}
}
//......
}
supervisorScope
suspend functionval launch = viewModelScope.launch(CoroutineExceptionHandler { _, _ ->
Log.e("TAG", "handler 1")
}) {
launch(CoroutineExceptionHandler { _, _ ->
Log.e("TAG", "handler 2 ")
}) {
delay(300)
supervisorScope { /// <<<< supervisor scope
launch {
try {
Log.e("TAG", "task 2 start")
delay(5000)
Log.e("TAG", "task 2 finished")
} catch (ex: Exception) {
Log.e("TAG", "task 2 ex $ex")
}
}
launch {
delay(2000)
throw Exception()
}
}
}
//....
}
Now task 2 will complete without raising JobCancellationException
Upvotes: 2
Reputation: 200196
Your answer is right there in the log:
task 2 ex kotlinx.coroutines.JobCancellationException: Parent job is Cancelling;
job=StandaloneCoroutine{Cancelling}@81a8e39
Look at the parent job: it's a StandaloneCoroutine
and not your SupervisorJob
.
When you write
launch(myJob!!, handler) { ... }
myJob
becomes the parent of the launched coroutine and the coroutine itself is always associated with a job the launch
function creates for it, of the type StandaloneCoroutine
. Inside this coroutine you launch more coroutines without explicitly specifying a parent, which means their parent is the coroutine's job. It is not a supervisor job and gets canceled.
Upvotes: 1