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?
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.