Careeroza
Structured Concurrency
Parent and Children
Structured concurrency means every coroutine has a parent, and coroutines form a tree. Three rules follow:
- A parent waits for all its children before it completes.
- Cancelling a parent cancels all children.
- If a child fails, the failure cancels the parent and its other children (unless a supervisor is used).
viewModelScope
└─ launch (loadScreen)
├─ async (profile)
├─ async (feed)
└─ launch (analytics)
cancel(viewModelScope) → every coroutine below is cancelled. No leaks.Parent Waits for Children
Example
The parent body ends early, but the parent job completes only after both children.
import kotlinx.coroutines.*
fun main() = runBlocking {
val parent = launch {
launch { delay(200); println("Child A done") }
launch { delay(100); println("Child B done") }
println("Parent body finished")
}
parent.join()
println("Parent completed: ${parent.isCompleted}")
}Output
Parent body finished Child B done Child A done Parent completed: true
Cancelling the Parent
Example
Cancelling the parent cancels every child. The child sees a CancellationException.
import kotlinx.coroutines.*
fun main() = runBlocking {
val parent = launch {
repeat(2) { i ->
launch {
try {
delay(1000)
println("Child $i finished") // never printed
} finally {
println("Child $i cancelled")
}
}
}
}
delay(100)
parent.cancelAndJoin()
println("Parent cancelled: ${parent.isCancelled}")
}Output
Child 0 cancelled Child 1 cancelled Parent cancelled: true
Tip: Structured concurrency is why you rarely leak coroutines in Android: when the user leaves the screen, viewModelScope is cancelled and all network calls started from it stop.