

State management is a cornerstone of dynamic UIs in Jetpack Compose. Among its many tools, remember and rememberSaveable are commonly used to manage state inside composable functions. Although they may appear similar, their behavior differs significantly when it comes to state persistence during lifecycle changes like screen rotations or process recreation.
Let’s explore these differences with practical examples and learn about advanced use cases such as using Bundle and custom Saver.
1. What is remember?
The remember function helps store a value in memory across recompositions. However, it does not persist the state during configuration changes, such as screen rotation or process recreation.
Example 1: Using remember
Imagine you’re building a simple counter app:
@Composable
fun CounterWithRemember() {
    var count by remember { mutableStateOf(0) }
    Column(horizontalAlignment = Alignment.CenterHorizontally) {
        Text(text = "Count: $count")
        Button(onClick = { count++ }) {
            Text("Increment")
        }
    }
}
Here, the counter value resets to 0 when you rotate the device because remember only retains the state during the current composition lifecycle.
2. What is rememberSaveable?
rememberSaveable is an extension of remember that retains the state across configuration changes by saving it into a Bundle, which is part of Android’s saved instance state mechanism.
Example 2: Using rememberSaveable
Let’s enhance our counter app to retain its value even after a screen rotation:
@Composable
fun CounterWithRememberSaveable() {
    var count by rememberSaveable { mutableStateOf(0) }
    Column(horizontalAlignment = Alignment.CenterHorizontally) {
        Text(text = "Count: $count")
        Button(onClick = { count++ }) {
            Text("Increment")
        }
    }
}
In this case, the counter value persists even if the screen is rotated because the value is saved into a Bundle and restored automatically.
3. Can We Use ViewModel for State Persistence?
Yes, you can! If the state is more complex or needs to be shared across multiple composables, using a ViewModel is often a better approach. Unlike rememberSaveable, a ViewModel persists state across configuration changes and process recreation as long as the app is not explicitly killed.
Example: Using ViewModel
class CounterViewModel : ViewModel() {
    var count by mutableStateOf(0)
        private set
    fun increment() {
        count++
    }
}@Composable
fun CounterWithViewModel(viewModel: CounterViewModel = viewModel()) {
    Column(horizontalAlignment = Alignment.CenterHorizontally) {
        Text(text = "Count: ${viewModel.count}")
        Button(onClick = { viewModel.increment() }) {
            Text("Increment")
        }
    }
}Here, CounterViewModel retains the counter state even if the system kills and recreates the activity.
4. What About Complex Objects?
rememberSaveable can handle basic data types like String, Int, or Boolean because they are serializable and can be stored in a Bundle. However, for custom or non-primitive data types, you need to use a Saver.
5. What is a Saver?
A Saver helps rememberSaveable store and restore complex objects by converting them into a format that can be saved into a Bundle (e.g., a Map or List).
Steps to Create a Custom Saver:
- Define the Object You Want to Save: 
 Create a data class or object for your state.
- Implement a Saver: 
 Write a- Saverthat converts the object into a savable format and restores it when needed.
- Use the Saver in - rememberSaveable:
 Pass the Saver to- rememberSaveablemanage your custom object’s state.
Example: Saving a Custom User Object
data class User(val name: String, val age: Int)
val UserSaver = Saver<User, Map<String, Any>>(
    save = { mapOf("name" to it.name, "age" to it.age) },
    restore = { User(it["name"] as String, it["age"] as Int) }
)
@Composable
fun CustomSaverExample() {
    var user by rememberSaveable(stateSaver = UserSaver) {
        mutableStateOf(User(name = "Akshay", age = 28))
    }
    Column(horizontalAlignment = Alignment.CenterHorizontally) {
        Text(text = "Name: ${user.name}, Age: ${user.age}")
        Button(onClick = { user = user.copy(age = user.age + 1) })  
        { Text("Increase Age") }
     }
}
Here, the User object is saved into a Map (compatible with a Bundle) and restored when needed.
Conclusion
To summarize:
- Use - rememberfor transient state that doesn’t need to persist across configuration changes.
- Use - rememberSaveablefor state that needs to survive configuration changes, leveraging Bundles.
- Use - ViewModelfor complex state management or shared state across composables.
- Create a Saver for non-primitive objects when using - rememberSaveable.
By combining these tools, you can effectively manage the state in your Jetpack Compose applications, ensuring a smooth and robust user experience.
Akshay Nandwana
Founder AndroidEngineers
You can connect with me on:
Book 1:1 Session here Click Here
Join our upcoming classes 
https://www.androidengineers.in/courses
Get the latest Android development articles delivered to your inbox.