I was under the impression if i use viewModelScope which internally uses SupervisorJob(), will keep the 3rd launch { } block running an will print API 3 as well. But the output is different? Why is this happening?
class HomeViewModel : ViewModel() {
private val _text = MutableLiveData<String>().apply {
value = "This is home Fragment"
}
val text: LiveData<String> = _text
val handler = CoroutineExceptionHandler { _, exception ->
println("API exception caught: $exception")
exception.printStackTrace()
}
fun test() {
viewModelScope.launch(handler) {
launch {
println("API 1 launch executing")
apiCall("API 1", 1000)
}
launch {
println("API 2 launch executing")
delay(1500)
throw NullPointerException("Exception")
}
launch {
println("API 3 launch executing")
apiCall("API 3", 2000)
}
delay(4000)
println("API no api its ended.")
}
}
private suspend fun apiCall(message: String, time: Long) {
delay(time)
println(message)
}
}
Output:
16:08:50.314 I API 1 launch executing
16:08:50.314 I API 2 launch executing
16:08:50.314 I API 3 launch executing
16:08:51.317 I API 1
16:08:51.819 I API exception caught: java.lang.NullPointerException: Exception
Your three parallel coroutines are all children of the single parent coroutine because you used its scope to launch them. That scope of the parent coroutine is a child of viewModelScope
and is not a supervisor so the child coroutines cannot fail independently.
Either launch each of the parallel coroutines directly from viewModelScope
or wrap the three of them with supervisorScope
to create a local supervisor for launching them as children.
Edit: Examples:
viewModelScope.launch(handler) {
viewModelScope.launch {
println("API 1 launch executing")
apiCall("API 1", 1000)
}
viewModelScope.launch {
println("API 2 launch executing")
delay(1500)
throw NullPointerException("Exception")
}
viewModelScope.launch {
println("API 3 launch executing")
apiCall("API 3", 2000)
}
delay(4000)
println("API no api its ended.")
}
Or
viewModelScope.launch(handler) {
supervisorScope {
launch {
println("API 1 launch executing")
apiCall("API 1", 1000)
}
launch {
println("API 2 launch executing")
delay(1500)
throw NullPointerException("Exception")
}
launch {
println("API 3 launch executing")
apiCall("API 3", 2000)
}
}
delay(4000)
println("API no api its ended.")
}