State Management in Jetpack Compose

Sep 10 2024 · Kotlin 1.9.22, Android 34, Android Studio Iguana | 2023.2.1 Patch 2

Lesson 05: Saving State

Demo

Episode complete

Play next episode

Next
Transcript

In this demo, you’ll learn how to use the Parcelize interface to be able to add data to the Bundle object. You’ll also see how to create custom rules to save an object.

To follow along, start Android Studio and open the 05-lesson-saving-state/Starter project. Build and run the project. The app shows a form to enter a new club member’s name and email.

Open the SignUpScreen.kt file containing the starter code. The SignUpScreen composable screen has two variables: memberName and memberEmail. Now, you’ll put the two variables in one data class called ClubMember.

First, create the ClubMember data class:

data class ClubMember(val name: String, val email: String)

Then replace the two variables with an object of the ClubMember data class.

var clubMember by rememberSaveable {
    mutableStateOf(ClubMember(name = "", email = ""))
  }

Replace the usage of memberName and memberEmail variables with the properties of the ClubMember data class.

@Composable
fun SignUpScreen(modifier: Modifier = Modifier) {
  var clubMember by rememberSaveable {
    mutableStateOf(ClubMember(name = "", email = ""))
  }
  Column(...) {
    ...
    FieldInputComponent(
      label = "Name",
      inputValue = clubMember.name,
      onInputValueChanged = { newValue ->
        clubMember = clubMember.copy(name = newValue)
      }
    )
    ...
    FieldInputComponent(
      label = "Email",
      inputValue = clubMember.email,
      onInputValueChanged = { newValue ->
        clubMember = clubMember.copy(email = newValue)

      }
    )
  }
}

Build and run the project.

Whoops! The app is crashing. When you look at the logs, the issue is that MutableState containing ClubMember(name=, email=) cannot be saved using the current SaveableStateRegistry. The default implementation only supports types which can be stored inside the Bundle.

To solve this, you’ll make the ClubMember data class parcelable. Open build.gradle file in the app module and add the kotlin-parcelize plugin.

id 'kotlin-parcelize'

Then click sync to apply this change.

Now, you can add the @Parcelize annotation to the ClubMember data class.

@Parcelize
data class ClubMember(val name: String, val email: String): Parcelable

Build and run the project.

The project was built successfully. Enter a new member’s name and email. Then, rotate the screen.

When you rotate the screen both name and email values are restored.

Kudos! You’ve used the Parcelize interface to save the ClubMember object. If for any reason you can’t use the Parcelize interface, you’d use mapSaver function to define a rule for converting an object to a set of values that can be added to the Bundle object. Now you’ll create a custom saver object using the mapSaver function.

First, you’ll remove the @Parcelize annotation from the ClubMember data class. Then create the custom saver object.

data class ClubMember(val name: String, val email: String)

val MemberSaver = run {
  val nameKey = "Name"
  val emailKey = "Email"
  mapSaver(
    save = { mapOf(nameKey to it.name, emailKey to it.email) },
    restore = {ClubMember(name = it[nameKey] as String, email = it[emailKey] as String)}
  )
}

First, you’ve created the keys that you’ll use to represent the values of the ClubMember class as a map. Then you use the save lambda to represent the ClubMember object as a map of values that will be added to the Bundle object individually. The restore lambda creates an object of ClubMember from the map that was created earlier.

Now, you can use the MemberSaver object to save the state during a configuration change:

var clubMember by rememberSaveable(stateSaver = MemberSaver) {
  mutableStateOf(ClubMember(name = "", email = ""))
}

Build and run the project. Enter name new member’s name and email. Then rotate the screen. Just like before, the state is persisted across the configuration change.

That ends this demo. Continue with the lesson for the summary.

See forum comments
Cinema mode Download course materials from Github
Previous: Instruction Next: Conclusion