The Truth About ViewModel and rememberSavable: Configuration Changes vs Process Death

Table of Contents

If you’ve built Android apps with Jetpack Compose, you’ve probably run into the question: Should I use ViewModel or rememberSaveable? Both help you keep state alive, but they work very differently depending on what’s happening to your app — like when the screen rotates or when the system kills your process.

This post will break down ViewModel and rememberSaveable, explain when to use each, and show real code examples so it finally clicks.

The Basics: Why State Preservation Matters

On Android, your app doesn’t always stay alive. Two big events affect your app’s state:

  1. Configuration changes — like screen rotations, language changes, or switching dark mode. The activity is destroyed and recreated, but the process usually stays alive.
  2. Process death — when Android kills your app’s process (e.g., to reclaim memory) and later restores it when the user comes back.

If you don’t handle these correctly, your users lose whatever they were doing. That’s where ViewModel and rememberSaveable come in.

remember: The Starting Point in Compose

At the simplest level, you use remember in Jetpack Compose to keep state alive across recompositions.

Kotlin
@Composable
fun CounterScreen() {
    var count by remember { mutableStateOf(0) }

    Button(onClick = { count++ }) {
        Text("Count: $count")
    }
}
  • Here, count won’t reset when Compose redraws the UI.
  • But if the device rotates (configuration change), the state is lost because remember only survives recompositions, not activity recreation.

That’s why we need more powerful tools.

rememberSaveable: Survives Configuration Changes and Process Death

rememberSaveable goes one step further. It automatically saves your state into a Bundle using Android’s saved instance state mechanism.

Kotlin
@Composable
fun CounterScreen() {
    var count by rememberSaveable { mutableStateOf(0) }

    Button(onClick = { count++ }) {
        Text("Count: $count")
    }
}

What happens here:

  • Rotate the screen? count survives.
  • App is killed and restored (process death)? count also survives, because it was written to the saved instance state.

Limitations:

  • Only works with data types that can be written to a Bundle (primitives, Strings, parcelables, etc.).
  • Not ideal for large objects or data fetched from a repository.

ViewModel: Survives Configuration Changes, Not Process Death

A ViewModel is a lifecycle-aware container designed to hold UI data. It’s tied to a LifecycleOwner like an activity or a navigation back stack entry.

Kotlin
class CounterViewModel : ViewModel() {
    var count by mutableStateOf(0)
}

@Composable
fun CounterScreen(viewModel: CounterViewModel = viewModel()) {
    Button(onClick = { viewModel.count++ }) {
        Text("Count: ${viewModel.count}")
    }
}

What happens here:

  • Rotate the screen? count survives. The same ViewModel instance is reused.
  • App is killed (process death)? count is lost. The ViewModel does not persist beyond process death.

Configuration Changes vs Process Death: Who Wins?

Here’s the clear breakdown:

When to Use rememberSaveable

Use rememberSaveable for small, lightweight UI state that:

  • Must survive both rotation and process death.
  • Can easily be serialized into a Bundle.

Examples:

  • Current tab index.
  • Form text fields.
  • Simple filter/sort options.

When to Use ViewModel

Use ViewModel for more complex or long-lived state that:

  • Doesn’t need to survive process death.
  • Might involve business logic, repositories, or data streams.
  • Should be scoped to the screen or navigation graph.

Examples:

  • Data loaded from a database or network.
  • Complex business logic.
  • State shared across multiple composables in the same screen.

Can You Combine Them? Yes.

Often, the best solution is to use ViewModel and rememberSaveable together.
 For example, a ViewModel manages your main UI state, but a few critical fields use rememberSaveable so they’re restored even after process death.

Kotlin
@Composable
fun FormScreen(viewModel: FormViewModel = viewModel()) {
    var userInput by rememberSaveable { mutableStateOf("") }

    Column {
        TextField(
            value = userInput,
            onValueChange = { userInput = it }
        )

        Button(onClick = { viewModel.submit(userInput) }) {
            Text("Submit")
        }
    }
}

Here:

  • userInput is lightweight and saved with rememberSaveable.
  • The ViewModel takes care of processing and persisting the submitted data.

Conclusion

The truth about ViewModel and rememberSaveable is simple once you think in terms of configuration changes vs process death:

  • remember → Only survives recomposition.
  • rememberSaveable → Survives both rotation and process death (small, serializable state).
  • ViewModel → Survives rotation, great for business logic, but not process death.

Use them in combination, not competition. Each tool has its place, and knowing when to reach for which makes your Compose apps more resilient, smoother, and user-friendly.

Skill Up: Software & AI Updates!

Receive our latest insights and updates directly to your inbox

Related Posts

error: Content is protected !!