You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

调用setApplicationLocales()时触发NavBackStackEntry ViewModel访问异常

解决Jetpack Compose切换语言时NavBackStackEntry ViewModel访问崩溃问题

问题根源

切换语言触发配置变更时,Activity会重建、Compose重组。你的代码在NavHost参数中直接调用hiltViewModel<AppViewModel>()获取NavController,这会导致重组时可能访问到已销毁的NavBackStackEntry关联的ViewModelStore,从而抛出异常。

解决方案

方案1:修正ViewModel与NavController的绑定方式

  1. 提前缓存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()
        }
    }
    
  2. 正确初始化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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 18:34:57