๐ŸŽจ Jetpack Compose

remember vs rememberSaveable

remember and rememberSaveable look almost identical, but they survive very different events. Pick the wrong one and your users lose what they typed when they rotate the phone, or when Android reclaims memory in the background.

โœ๏ธ Yunok Tech ๐Ÿ“… Updated โฑ 3 min read ๐ŸŽฏ Intermediate
On this page
  1. What each one survives
  2. How rememberSaveable works
  3. Custom types with Parcelize
  4. Custom Savers
  5. Keys: resetting remembered values
  6. Limits and when to use a ViewModel instead
  7. How to test process death
  8. Choosing in practice
  9. Frequently asked questions
  10. Conclusion

A user types a long review, rotates the phone to see it better, and the text field is empty. Or they switch to their banking app to copy an OTP, come back, and the screen has reset. Both bugs come from choosing remember where rememberSaveable (or a ViewModel) was needed.

What each one survives

EventrememberrememberSaveableViewModelViewModel + SavedStateHandle
Recompositionโœ…โœ…โœ…โœ…
Leaving composition (e.g. if hides it)โŒโŒ (unless in a saveable state holder, as in navigation)โœ…โœ…
Configuration change (rotation, dark mode, locale)โŒโœ…โœ…โœ…
Process death (system kills app in background)โŒโœ…โŒโœ…
User closes app from recents / back from rootโŒโŒโŒโŒ

For data that must survive even the user closing the app, such as drafts or settings, persist it with Room or DataStore.

Survival levels of Compose state Nested boxes from smallest to largest lifetime: remember survives recomposition; rememberSaveable also survives configuration changes and process death via the saved instance state Bundle; Room or DataStore persists across app restarts. Room / DataStore: survives app restarts rememberSaveable: + rotation + process death (Bundle) remember: recomposition only
Choose the smallest lifetime that still protects the user's work.

How rememberSaveable works

rememberSaveable stores its value in the saved instance state Bundle, the same mechanism Activities use. The value must therefore be saveable: primitives, Strings, and Parcelable or Serializable types, or you provide a Saver.

Common usagesKotlin
@Composable
fun ReviewForm() {
    var text by rememberSaveable { mutableStateOf("") }              // String: saveable
    var rating by rememberSaveable { mutableIntStateOf(0) }          // Int: saveable
    var showTips by remember { mutableStateOf(true) }                // transient UI hint: remember is fine
    // ...
}

Custom types with Parcelize

Parcelable stateKotlin
@Parcelize
data class DateRange(val startEpochDay: Long, val endEpochDay: Long) : Parcelable

var range by rememberSaveable { mutableStateOf(DateRange(0, 0)) }

This requires the kotlin-parcelize Gradle plugin.

Custom Savers

mapSaver / listSaverKotlin
data class Filters(val query: String, val onlyUnread: Boolean)

val FiltersSaver = listSaver<Filters, Any>(
    save = { listOf(it.query, it.onlyUnread) },
    restore = { Filters(it[0] as String, it[1] as Boolean) },
)

var filters by rememberSaveable(stateSaver = FiltersSaver) { mutableStateOf(Filters("", false)) }

Keys: resetting remembered values

remember with keysKotlin
@Composable
fun ProductScreen(productId: String) {
    // Recreated when productId changes, otherwise reused
    val formatter = remember(productId) { PriceFormatter(productId) }
    // Saved selection resets when navigating to a different product
    var selectedSize by rememberSaveable(productId) { mutableStateOf<String?>(null) }
}

Limits and when to use a ViewModel instead

  • Bundle size is limited. Saving large lists or bitmaps can cause TransactionTooLargeException. Save IDs or small input, and reload data from the repository.
  • Business logic doesn't belong in composables. If state needs loading, validation or saving, put it in a ViewModel, using SavedStateHandle for the parts that must survive process death.
  • Don't save derived values. Save the inputs and recompute the rest.

How to test process death

  1. Run the app, type into the form, then press Home.
  2. Run adb shell am kill com.your.package (it only kills background apps), or enable Don't keep activities.
  3. Reopen the app from recents. Everything in rememberSaveable and SavedStateHandle should be restored.

Choosing in practice

Text the user typed

rememberSaveable, or SavedStateHandle in the ViewModel if the screen logic uses it.

Animation or tooltip flags

remember. Losing it on rotation is harmless.

Scroll position

rememberLazyListState() already uses a saver internally.

Frequently asked questions

Does rememberSaveable survive navigating away and back?

Inside Navigation Compose or Navigation 3 destinations, saveable state is kept for back stack entries, so returning to a screen restores it. Outside such holders, leaving composition discards it.

Is rememberSaveable slower?

Only slightly: it registers with the saved-state registry. Use it where survival matters, not for every value.

Can I rememberSaveable a ViewModel?

No. ViewModels have their own lifecycle. Use viewModel() or hiltViewModel() instead.

Conclusion

remember survives recomposition. rememberSaveable also survives configuration changes and process death, via the Bundle. Use saveable state for user input, ViewModels with SavedStateHandle for screen logic, and Room or DataStore for anything that must outlive the session.

Next step: run work at the right time with Side Effects in Compose.

Official references

๐Ÿ“ฑ Apps built by Yunok Tech

Real Android apps on Google Play, free to download.

See all our apps โ†’

Ready to build real Android applications?

Jetpack Compose clicks once you build real screens with real state. Practise modern Android UI development on projects that go beyond toy examples.

Move beyond theory and strengthen your Android development skills with Yunoktech's Android course. Learn core concepts, practical implementation, modern Android development techniques, and the reasoning behind building maintainable applications.

Explore the Android course and take your next step as an Android developer.

Share: LinkedIn X / Twitter WhatsApp