调用setApplicationLocales()时触发NavBackStackEntry ViewModel访问异常
问题根源
切换语言触发配置变更时,Activity会重建、Compose重组。你的代码在NavHost参数中直接调用hiltViewModel<AppViewModel>()获取NavController,这会导致重组时可能访问到已销毁的NavBackStackEntry关联的ViewModelStore,从而抛出异常。
解决方案
方案1:修正ViewModel与NavController的绑定方式
提前缓存ViewModel实例
在顶层Composable中提前获取并缓存AppViewModel,避免每次重组重复获取:// MainActivity的setContent内 val appViewModel = hiltViewModel<AppViewModel>() // 确保NavController绑定当前Activity的生命周期 val navController = appViewModel.controller.apply { setLifecycleOwner(this@MainActivity) setOnBackPressedDispatcher(this@MainActivity.onBackPressedDispatcher) } NavHost( navController = navController, startDestination = LogInRoute ) { composable<LogInRoute> { LoginScreen() } }正确初始化ViewModel中的NavController
在AppViewModel中添加初始化方法,确保NavController关联正确的生命周期依赖:class AppViewModel @Inject constructor( private val context: Context ) : ViewModel() { lateinit var controller: NavHostController fun initNavController( lifecycleOwner: LifecycleOwner, onBackPressedDispatcher: OnBackPressedDispatcher ) { controller = NavHostController(context).apply { setLifecycleOwner(lifecycleOwner) setOnBackPressedDispatcher(onBackPressedDispatcher) } } }然后在MainActivity中调用初始化:
val appViewModel = hiltViewModel<AppViewModel>() if (!::appViewModel.controller.isInitialized) { appViewModel.initNavController(this, onBackPressedDispatcher) }
方案2:改用rememberNavController()(更简洁推荐)
NavHostController的标准用法是在Composable中用rememberNavController()创建,它会自动处理配置变更和生命周期绑定:
// MainActivity的setContent内 val navController = rememberNavController() NavHost( navController = navController, startDestination = LogInRoute ) { composable<LogInRoute> { LoginScreen() } }
如果需要在ViewModel中使用NavController,可通过函数参数传递,或在Composable中用LocalNavController.current获取后调用ViewModel方法。
验证修复
切换语言后,Activity重建时,NavController会正确关联新的生命周期和NavBackStackEntry,不会再触发已销毁实例的访问异常。
内容的提问来源于stack exchange,提问作者dart78
相关产品推荐
相关产品推荐

