Structured Concurrency in Kotlin - coroutineScope, Job & Cancellation
Structured concurrency ensures all coroutines are properly tracked and cancelled. Master Job, coroutineScope, and cancellation.
Scoped Coroutines
coroutineScope creates a scope that waits for all children:
suspend fun fetchUserData(): UserData = coroutineScope {
val userDeferred = async { fetchUser() }
val postsDeferred = async { fetchPosts() }
// Both requests run in parallel, but scope waits for both
UserData(
user = userDeferred.await(),
posts = postsDeferred.await()
)
}
// Exceptions in either async are propagated
Job and Cancellation
val job = viewModelScope.launch {
try {
repeat(100) { i ->
println("Working $i")
delay(1000)
}
} catch (e: CancellationException) {
println("Job cancelled")
throw e // Re-throw to propagate
} finally {
println("Cleanup")
}
}
// Cancel the job
job.cancel()
SupervisorJob for Independent Children
val supervisor = SupervisorJob()
val scope = CoroutineScope(Dispatchers.Main + supervisor)
scope.launch {
throw Exception("Child 1 failed")
}
scope.launch {
delay(1000)
println("Child 2 still runs") // Not affected by Child 1 failure
}
Proper ViewModel Cleanup
class MyViewModel : ViewModel() {
override fun onCleared() {
viewModelScope.cancel()
}
}
Best Practices
- Use viewModelScope for ViewModel coroutines
- Catch CancellationException and re-throw
- Use coroutineScope for parallel tasks
- Use SupervisorJob for independent operations
- Always provide proper finally cleanup
8 Android app templates on Gumroad
Top comments (0)