Jetpack Compose + Navigation: rememberSaveable loses state on rotate

Viewed 2446

I've encountered a strange behavior with Jetpack Compose in combination with Navigation: If you use rememberSaveable inside some navigation composable, then the state is not saved as promised (e.g. it is lost after rotation). Here is a simple example:

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.material.MaterialTheme
import androidx.compose.material.TextField
import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController
import androidx.compose.runtime.getValue
import androidx.compose.runtime.setValue

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            MaterialTheme {
                MyScreen()
            }
        }
    }
}

@Composable
fun MyScreen() {
    val navController = rememberNavController()
    NavHost(navController = navController, startDestination = "xyz") {
        composable("xyz") {
            var value by rememberSaveable { mutableStateOf("") }
            TextField(value = value, onValueChange = { value = it })
        }
    }
}

The above code produces a single text field in which one can type. Once one rotates the screen, the typed text is lost, even though the value should be saved by rememberSaveable.

Investigating a little bit, I noticed the following:

  • The problem is really the NavHost. If one moves the line defining the variable "value" to the top of "MyScreen()" (outside of the NavHost) then everything works as intended.

  • The real issue seems to be that the composable variable "currentCompositeKeyHash" is not retained after configuration changes inside the NavHost. This variable is used as a key for the savedInstanceBundle to retrieve the saved value by rememberSaveable, thus the state gets lost. In particular, if one explicitly specifies a key in rememberSaveable, then everything works as expected.

Is this a bug or am I misunderstanding something?

1 Answers

Update:

Version 2.4.0-alpha07 has been released and fixes the issue:

implementation "androidx.navigation:navigation-compose:2.4.0-alpha07"

Original answer:

This is a known issue with version 2.4.0-alpha05 and 2.4.0-alpha06 of androidx.navigation:navigation-compose. The current solution is to downgrade to 2.4.0-alpha04:

implementation "androidx.navigation:navigation-compose:2.4.0-alpha04"

According to the issue tracker, the issue has been fixed in version 2.4.0-alpha07, which hopefully will be released soon.

Related