如何在Compose Navigation中通过Koin注入实现共享ViewModel?
你的代码中两个页面会创建BLEIoTViewModel新实例的核心原因是未明确指定共享的导航作用域,当前的sharedViewModel函数逻辑存在疏漏,导致无法复用同一ViewModel实例。以下是修正方案:
问题根源
你当前的NavHost没有给根导航图命名,导致destination.parent?.route可能返回null,此时函数会直接调用koinViewModel()——这个方法默认以当前页面的NavBackStackEntry作为ViewModelStoreOwner,每个页面自然会生成新的ViewModel实例。
修正步骤
1. 给根导航图指定命名路由
修改NavHost,为根导航图添加明确的route参数,让所有子页面归属同一作用域:
@Composable fun NavigationSystem() { val navController = rememberNavController() NavHost( navController = navController, startDestination = "scan", route = "root_nav_graph" // 新增根导航图路由 ) { composable("scan") { val viewModel: BLEIoTViewModel = it.sharedViewModel(navController) // ... 原有代码 } composable("config") { val viewModel: BLEIoTViewModel = it.sharedViewModel(navController) // ... 原有代码 } } }
2. 修正sharedViewModel扩展函数逻辑
确保始终获取根导航图的BackStackEntry作为共享作用域,避免依赖可能为空的父路由:
@Composable inline fun <reified T : ViewModel> NavBackStackEntry.sharedViewModel( navController: NavHostController, rootNavRoute: String = "root_nav_graph" // 与根导航图路由对应 ): T { // 记住根导航图的BackStackEntry,确保跨页面复用同一实例 val rootBackStackEntry = remember(rootNavRoute) { navController.getBackStackEntry(rootNavRoute) } // 基于根BackStackEntry获取ViewModel,实现共享 return koinViewModel(viewModelStoreOwner = rootBackStackEntry) }
3. 确认Koin模块的ViewModel声明正确
在你的Koin模块中,确保ViewModel的声明符合Koin的规范:
val bleModule = module { // 如果ViewModel有依赖(如Repository),通过get()注入 viewModel { BLEIoTViewModel(get()) } // 无依赖则直接写:viewModel { BLEIoTViewModel() } }
原理说明
当指定根导航图的路由后,两个页面都会获取同一个根BackStackEntry作为ViewModelStoreOwner,Koin会基于这个全局作用域创建并复用ViewModel实例,从而实现跨页面的数据共享。
内容的提问来源于stack exchange,提问作者Fiqri Hafzain
相关产品推荐
相关产品推荐

