When working with Kotlin coroutines in Android, picking the right scope is crucial for keeping your app efficient, resilient, and leak-free. Two of the most common scopes you’ll see are SupervisorScope and viewModelScope. This article walks you through their differences, shows you concrete examples, and helps you decide which to use.
Example
class MyViewModel : ViewModel() {
// viewModelScope: tied to ViewModel and runs on Dispatchers.Main
fun loadUiData() {
viewModelScope.launch {
// Fetch user profile for the screen
val profile = fetchUserProfile()
// Update LiveData / UI state
}
}
// Using SupervisorScope inside a suspending function
suspend fun fetchAllData() = supervisorScope {
launch { fetchOrders() } // Task A
launch { fetchMessages() } // Task B
launch { fetchSettings() } // Task C
// Even if fetchMessages() fails, A & C keep running
}
}
Comparison
Aspect | SupervisorScope | viewModelScope |
---|---|---|
Lifecycle | Manual—lives as long as its coroutine is active | Tied to ViewModel; cancels on onCleared() |
Default Dispatcher | Inherits parent context (you choose Main, IO, or Default) | Always Dispatchers.Main (UI thread) |
Failure Isolation | One child fails → only that child is canceled | Backed by SupervisorJob so siblings survive each other’s errors, but uncaught exceptions still bubble up and cancel the whole scope unless handled |
Use Case | Independent parallel tasks (e.g. multiple network calls) | UI-related work that must stop when the screen goes away |
Exception Handling
SupervisorScope
- Use try/catch per child or attach a CoroutineExceptionHandler
- Provides fine-grained control over error handling
- Each child coroutine can handle its own exceptions independently
viewModelScope
- Wrap each launch in try/catch or supply a handler to prevent scope-wide cancellation
- Built-in error handling through SupervisorJob
- Exceptions can still cancel the entire scope if not handled
Summary
SupervisorScope
- Best for truly independent tasks on any dispatcher
- One failure doesn’t kill its siblings
- You manage its lifecycle manually
viewModelScope
- Built into Android’s ViewModel and always runs on the main thread
- Automatically cancels everything when the ViewModel is destroyed
- Still lets sibling coroutines survive each other’s failures—provided you catch or handle exceptions
Bottom Line
- Use SupervisorScope for isolated, parallel work on whatever dispatcher you need
- Use viewModelScope for screen-tied, UI-thread coroutines that should auto-cancel when the ViewModel goes away
Related Articles
To learn more about coroutines and Android development:
- Kotlin Coroutines: Dispatchers - Learn about different dispatchers and when to use them
- Jetpack Compose: Architecture - Understand how to structure your Android app
- Jetpack Compose: Composition Phase - Learn about UI rendering and state management
- Jetpack Compose: Testing & Semantics - Discover how to test your coroutine-based code