Careeroza
SupervisorJob
Job vs SupervisorJob
Job(): SupervisorJob(): parent parent ├─ child A ✗ fails ├─ child A ✗ fails ├─ child B ✗ cancelled ├─ child B ✓ keeps running └─ parent ✗ cancelled └─ parent ✓ still active
viewModelScope and lifecycleScope use a SupervisorJob, so one failed request does not stop other work on the screen.
Example
Example
import kotlinx.coroutines.*
fun main() = runBlocking {
val log = CoroutineExceptionHandler { _, e -> println(" logged: ${e.message}") }
println("With Job():")
val normal = CoroutineScope(Job() + log)
val a1 = normal.launch { delay(50); error("A failed") }
val b1 = normal.launch { delay(100); println(" B finished") }
joinAll(a1, b1)
println(" scope active: ${normal.isActive}")
println("With SupervisorJob():")
val supervised = CoroutineScope(SupervisorJob() + log)
val a2 = supervised.launch { delay(50); error("A failed") }
val b2 = supervised.launch { delay(100); println(" B finished") }
joinAll(a2, b2)
println(" scope active: ${supervised.isActive}")
supervised.cancel()
}Output
With Job(): logged: A failed scope active: false With SupervisorJob(): logged: A failed B finished scope active: true
Note: launch(SupervisorJob()) { ... } is a common mistake: it makes the new coroutine a child of a fresh SupervisorJob and breaks the link to the parent scope. Use supervisorScope { } or a scope created with SupervisorJob() instead.