Jetpack Compose嵌套导航图触发ViewModelStore需在setGraph前设置异常如何解决
问题根因
你错误地将全局根NavHostController同时绑定了两个独立的NavHost实例:根导航图的NavHost已经完成setGraph初始化,你在AppScaffold内部再次使用同一个NavController创建第二个NavHost时,重复触发setGraph调用,就会抛出ViewModelStore should be set before setGraph call异常。
修复方案
按照嵌套导航图的规范调整结构,移除AppScaffold内部的冗余NavHost,将底部导航页面直接定义在bottomBar子导航图中,具体修改如下:
1. 修改AppScaffold.kt
移除内部的NavHost,仅保留Scaffold框架,将内容区域作为参数传入:
@Composable fun AppScaffold( navController: NavHostController, content: @Composable (PaddingValues) -> Unit ) { val scaffoldState = rememberScaffoldState() Scaffold( bottomBar = { BottomBar(mainNavController = navController) }, scaffoldState = scaffoldState, content = content ) }
2. 重写BottomBarNavGraph.kt
直接将三个底部导航页面定义在子导航图中,外层包裹AppScaffold:
fun NavGraphBuilder.bottomBarNavGraph( navController: NavHostController, userViewModel: UserViewModel ) { navigation( startDestination = NavigationScreen.EmergencyCallScreen.route, route = BOTTOM_BAR_GRAPH_ROUTE ) { composable(NavigationScreen.EmergencyCallScreen.route) { AppScaffold(navController = navController) { padding -> EmergencyCallScreen( modifier = Modifier.padding(padding), navController = navController, loginViewModel = userViewModel ) } } composable(NavigationScreen.ChatScreen.route) { AppScaffold(navController = navController) { padding -> ChatScreen(modifier = Modifier.padding(padding)) } } composable(NavigationScreen.SettingsScreen.route) { AppScaffold(navController = navController) { padding -> SettingsScreen( modifier = Modifier.padding(padding), navController = navController, loginViewModel = userViewModel ) } } } }
3. 调整跳转逻辑
- 登录/注册页跳转到指定底部页面:直接调用
navController.navigate(NavigationScreen.你需要跳转的页面.route)即可 - 底部页面跳回登录页:调用以下代码清除底部导航栈,避免回退回到应用内部页面:
navController.navigate(LOGIN_GRAPH_ROUTE) { popUpTo(BOTTOM_BAR_GRAPH_ROUTE) { inclusive = true } }
- 根
NavHost的起始目的地可根据登录状态动态设置:未登录时设置为LOGIN_GRAPH_ROUTE,已登录时设置为BOTTOM_BAR_GRAPH_ROUTE即可。
4. 可选优化
你可以删除Screen类中冗余的AppScaffold路由配置,本次调整后不会再用到该路由。
内容的提问来源于stack exchange,提问作者talhaoz
相关产品推荐
相关产品推荐

