Android Navigation中从A到B再返回时如何保留Screen A的状态?
问题根源
你遇到的状态丢失问题,核心原因是每次从Screen B返回Screen A时,ScreenViewModel被重新创建了。
在你的导航图代码中,composable的lambda块会在Screen A每次进入(包括从回栈恢复)时重新执行,而你在这里直接通过val viewModel = ScreenViewModel()创建实例,导致每次都生成全新的ViewModel,之前的计数器状态自然无法保留。即使Screen A在导航回栈中,Composable的重组机制也会重新执行这段代码,生成新的ViewModel实例。
解决方案
要让ViewModel与导航目的地的生命周期绑定,确保回栈中的页面保留状态,有两种常用方式:
方案1:使用viewModel()函数(推荐)
使用Jetpack Compose提供的viewModel()函数获取ViewModel,它会自动将ViewModel与当前导航目的地的BackStackEntry绑定,只要目的地在回栈中,ViewModel就不会被销毁。
修改导航图代码:
fun Navigation(navController: NavHostController) { NavHost(navController = navController, startDestination = Screens.Screen1.title) { composable(route = Screens.Screen1.title) { // 使用viewModel()函数获取实例,而非直接new val viewModel: ScreenViewModel = viewModel() Screen1(viewModel, count = viewModel.count.collectAsState()) } composable(route = Screens.Screen2.title) { Screen2( onButtonClick = { navController.navigateUp() } ) } } }
方案2:手动绑定BackStackEntry
如果需要更自定义的ViewModel创建逻辑,可以直接使用BackStackEntry作为ViewModelStoreOwner,通过ViewModelProvider创建实例,并用remember确保实例不会重复创建:
fun Navigation(navController: NavHostController) { NavHost(navController = navController, startDestination = Screens.Screen1.title) { composable(route = Screens.Screen1.title) { backStackEntry -> val viewModel = remember(backStackEntry) { ViewModelProvider(backStackEntry).get(ScreenViewModel::class.java) } Screen1(viewModel, count = viewModel.count.collectAsState()) } composable(route = Screens.Screen2.title) { Screen2( onButtonClick = { navController.navigateUp() } ) } } }
优化建议
你还可以简化Screen1的代码,直接在Composable内部收集状态,避免额外的参数传递:
@Composable fun Screen1(viewModel: ScreenViewModel = viewModel()) { val count by viewModel.count.collectAsState() Column { Button(onClick = { viewModel.onButtonPressed() }) { Text("Counter") } Text(count.toString()) } }
对应的导航图代码可以简化为:
composable(route = Screens.Screen1.title) { Screen1() }
内容的提问来源于stack exchange,提问作者archviz_fan
相关产品推荐
相关产品推荐

