Retain API in Jetpack Compose

Published: (December 25, 2025 at 08:05 PM EST)
3 min read
Source: Dev.to

Source: Dev.to

Cover image for Retain API in Jetpack Compose

🚀 Mastering the Retain API in Jetpack Compose: Why & How It Matters

In modern Android development with Jetpack Compose, managing state effectively—especially across configuration changes—is crucial for building resilient and fluid UI experiences. The Retain API helps you preserve state without manual save/restore logic.

What is the Retain API?

The Retain API in Jetpack Compose lets you preserve state across configuration changes (e.g., device rotation), process death, and navigation lifecycle events. Unlike remember or mutableStateOf, which exist only for the lifetime of a composition, the Retain API ties state to a lifecycle owner (such as a ViewModel or NavBackStackEntry), ensuring it survives these events.

Why Use the Retain API?

  • Survives configuration changes (e.g., screen rotation)
  • Works with process‑death restoration
  • Integrates with ViewModels & Navigation
  • ✅ More concise and Compose‑friendly than onSaveInstanceState

It simplifies state persistence without boilerplate, letting you focus on building features.

Core Concepts

APIPurpose
rememberRetainedPersists state across composition & config changes
RetainedSaveableStateRegistryHandles the save/restore lifecycle
SavedStateHandleWorks with ViewModels for state persistence

Example: Persist Form State with Retain API

Without Retain API (Problem)

@Composable
fun ProfileForm() {
    var name by remember { mutableStateOf("") }
    var email by remember { mutableStateOf("") }

    Column {
        TextField(value = name, onValueChange = { name = it }, label = { Text("Name") })
        TextField(value = email, onValueChange = { email = it }, label = { Text("Email") })
    }
}

When the device rotates, the state is lost.

With Retain API

@Composable
fun ProfileFormRetained() {
    val retainedName = rememberRetained { mutableStateOf("") }
    val (name, setName) = retainedName

    val retainedEmail = rememberRetained { mutableStateOf("") }
    val (email, setEmail) = retainedEmail

    Column {
        TextField(value = name, onValueChange = setName, label = { Text("Name") })
        TextField(value = email, onValueChange = setEmail, label = { Text("Email") })
    }
}

Now the state survives rotation with less code.

Using Retain API with ViewModel

class ProfileViewModel(
    savedStateHandle: SavedStateHandle
) : ViewModel() {
    var name by savedStateHandle.getState("name") { "" }
    var email by savedStateHandle.getState("email") { "" }
}
@Composable
fun ProfileScreen(vm: ProfileViewModel = hiltViewModel()) {
    Column {
        TextField(
            value = vm.name,
            onValueChange = { vm.name = it },
            label = { Text("Name") }
        )
        TextField(
            value = vm.email,
            onValueChange = { vm.email = it },
            label = { Text("Email") }
        )
    }
}

Storing state in a ViewModel with SavedStateHandle ensures process‑death restoration as well as rotation persistence.

Best Practices

  • ✨ Favor rememberRetained for UI state that must survive recomposition.
  • ✨ Use SavedStateHandle with a ViewModel for process‑death and navigation state.
  • ✨ Scope retained state to where it logically belongs (e.g., ViewModel vs. Composable).
  • Android Dev — Jetpack Compose State & State Hoisting
  • SavedStateHandle in ViewModel
  • Jetpack Compose API Reference

Final Thoughts

The Retain API is an under‑the‑hood feature that makes real‑world Compose apps robust and maintainable. Whether you’re handling forms, navigation state, or UI flags, understanding how to retain state confidently will boost both developer productivity and user experience.

Happy Composing! 🎨📱

Back to Blog

Related posts

Read more »