100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
Kotlin

ViewModel Basics

What Android's ViewModel class does, how it survives configuration changes, and how to create and scope ViewModels correctly in a Compose app.

Architecture & ViewModelBeginner8 min readJul 8, 2026
Analogies

ViewModel Basics

ViewModel is a Jetpack Architecture Components class designed to hold and manage UI-related data in a way that survives configuration changes like screen rotation, without needing to be manually saved and restored via onSaveInstanceState. When an Activity is destroyed and recreated due to a configuration change, the ViewModel instance associated with it is retained by the framework and handed back to the newly created Activity/composable, rather than being recreated from scratch — this is fundamentally different from a plain class field in a composable, which is lost and reinitialized on every recomposition or process restart unless separately preserved.

🏏

Cricket analogy: A ViewModel is like the official match scorebook that survives even if the stadium's power briefly cuts and the big screen reboots (rotation) — the scores are retained and handed straight back, unlike a hand-scribbled note on a fan's scorecard that's lost when they leave their seat.

Obtaining a ViewModel in Compose

In a Compose app, a ViewModel is typically obtained with the viewModel() composable function from androidx.lifecycle.viewmodel.compose, or hiltViewModel() if using Hilt for dependency injection. Both functions look up (or create, on first call) a ViewModel instance scoped to the nearest ViewModelStoreOwner in the composition — usually the hosting Activity, or a specific NavBackStackEntry when scoped to a navigation destination.

🏏

Cricket analogy: Obtaining a ViewModel via viewModel() is like a scorer requesting the official scorebook for 'Match 12' from the pavilion — if it already exists it's handed over as-is, if not a fresh one is created, scoped to that specific match rather than to the stadium overall.

kotlin
class CounterViewModel : ViewModel() {
    private val _count = MutableStateFlow(0)
    val count: StateFlow<Int> = _count.asStateFlow()

    fun increment() {
        _count.update { it + 1 }
    }
}

@Composable
fun CounterScreen(viewModel: CounterViewModel = viewModel()) {
    val count by viewModel.count.collectAsStateWithLifecycle()

    Column(
        modifier = Modifier.fillMaxSize(),
        horizontalAlignment = Alignment.CenterHorizontally,
        verticalArrangement = Arrangement.Center
    ) {
        Text(text = "Count: $count", style = MaterialTheme.typography.headlineLarge)
        Spacer(modifier = Modifier.height(16.dp))
        Button(onClick = { viewModel.increment() }) {
            Text("Increment")
        }
    }
}

Scoping: Activity, screen, and navigation graph

By default, viewModel() scopes to the nearest ViewModelStoreOwner, which in a single-Activity Compose app is usually the Activity itself unless a NavBackStackEntry is explicitly passed — meaning calling viewModel() with the same type from two different composables inside the same NavHost destination returns the same instance, while different destinations get their own instances by default (each NavBackStackEntry is itself a ViewModelStoreOwner). Passing a specific back stack entry (e.g. the nested graph's entry) lets multiple screens share one ViewModel instance intentionally, as covered in nested navigation and back stack management.

🏏

Cricket analogy: Scoping a ViewModel to the Activity is like every commentary box in the same stadium sharing one master scoreboard by default, so they all see the same numbers; scoping to a NavBackStackEntry is like giving each individual match its own dedicated scoreboard so simultaneous games don't mix up scores.

A useful mental model: a plain remember { ... } value in a composable is like a sticky note that gets thrown away and rewritten whenever the composable itself is discarded (e.g. on rotation, since the default Activity recreates), whereas a ViewModel is like a filing cabinet drawer that the framework specifically keeps safe across that kind of disruption and only clears out when the owning scope (Activity or back stack entry) is truly finished.

ViewModel survives configuration changes but does NOT survive process death (the OS killing the app process entirely while in the background to reclaim memory). For state that must survive process death, combine ViewModel with SavedStateHandle, or persist to disk (Room, DataStore).

Lifecycle and cleanup

A ViewModel's onCleared() callback is invoked once its owning scope is permanently destroyed — the Activity finishing (not just rotating) or the NavBackStackEntry being popped off the back stack for good — and is the right place to cancel any long-running work that isn't already tied to viewModelScope (which is itself automatically cancelled at this point, cancelling any coroutines launched within it).

🏏

Cricket analogy: onCleared() firing when the Activity finishes (not rotates) is like the scorebook only being formally closed and archived when the match is abandoned for good, not merely when the stadium's lights briefly flicker — that's the moment to cancel any pending, unfinished scoring tasks.

  • ViewModel holds UI-related data that survives configuration changes like rotation, unlike plain composable state.
  • In Compose, obtain a ViewModel via viewModel() or hiltViewModel(), scoped to the nearest ViewModelStoreOwner.
  • By default, ViewModels scope to the Activity or to a specific NavBackStackEntry when explicitly passed one.
  • ViewModel survives configuration changes but NOT process death — use SavedStateHandle or persistence for that.
  • onCleared() runs when the owning scope is permanently destroyed, and automatically cancels viewModelScope coroutines.
  • Passing the same NavBackStackEntry to viewModel() from multiple screens lets them intentionally share one instance.

Practice what you learned

Was this page helpful?

Topics covered

#Kotlin#AndroidWithJetpackComposeStudyNotes#MobileDevelopment#ViewModelBasics#ViewModel#Obtaining#Compose#Scoping#StudyNotes#SkillVeris