Jetpack Compose + Navigation:rememberSaveable 在旋转时丢失状态
Jetpack Compose + Navigation: rememberSaveable loses state on rotate
我在结合使用 Jetpack Compose 和 Navigation 时遇到了一个奇怪的行为:如果您在某些导航可组合项中使用 rememberSaveable,则状态不会按承诺保存(例如,它在旋转后丢失)。这是一个简单的例子:
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 })
}
}
}
以上代码生成一个可以键入的文本字段。一旦旋转屏幕,输入的文本就会丢失,即使该值应该由 rememberSaveable 保存。
稍微调查了一下,我注意到以下几点:
确实是 NavHost 的问题。如果将定义变量“value”的行移动到“MyScreen()”的顶部(在 NavHost 之外),那么一切都会按预期进行。
真正的问题似乎是在 NavHost 内部的配置更改后,可组合变量“currentCompositeKeyHash”未保留。此变量用作 savedInstanceBundle 的键以通过 rememberSaveable 检索保存的值,因此状态丢失。特别是,如果在 rememberSaveable 中明确指定一个键,那么一切都会按预期进行。
这是一个错误还是我误解了什么?
更新:
版本 2.4.0-alpha07
已发布并修复了问题:
implementation "androidx.navigation:navigation-compose:2.4.0-alpha07"
原回答:
这是 androidx.navigation:navigation-compose
版本 2.4.0-alpha05
和 2.4.0-alpha06
的已知问题。目前的解决方案是降级到2.4.0-alpha04
:
implementation "androidx.navigation:navigation-compose:2.4.0-alpha04"
According to the issue tracker,该问题已在版本 2.4.0-alpha07
中修复,希望很快发布。
我在结合使用 Jetpack Compose 和 Navigation 时遇到了一个奇怪的行为:如果您在某些导航可组合项中使用 rememberSaveable,则状态不会按承诺保存(例如,它在旋转后丢失)。这是一个简单的例子:
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 })
}
}
}
以上代码生成一个可以键入的文本字段。一旦旋转屏幕,输入的文本就会丢失,即使该值应该由 rememberSaveable 保存。
稍微调查了一下,我注意到以下几点:
确实是 NavHost 的问题。如果将定义变量“value”的行移动到“MyScreen()”的顶部(在 NavHost 之外),那么一切都会按预期进行。
真正的问题似乎是在 NavHost 内部的配置更改后,可组合变量“currentCompositeKeyHash”未保留。此变量用作 savedInstanceBundle 的键以通过 rememberSaveable 检索保存的值,因此状态丢失。特别是,如果在 rememberSaveable 中明确指定一个键,那么一切都会按预期进行。
这是一个错误还是我误解了什么?
更新:
版本 2.4.0-alpha07
已发布并修复了问题:
implementation "androidx.navigation:navigation-compose:2.4.0-alpha07"
原回答:
这是 androidx.navigation:navigation-compose
版本 2.4.0-alpha05
和 2.4.0-alpha06
的已知问题。目前的解决方案是降级到2.4.0-alpha04
:
implementation "androidx.navigation:navigation-compose:2.4.0-alpha04"
According to the issue tracker,该问题已在版本 2.4.0-alpha07
中修复,希望很快发布。