Hilt使用hiltNavGraphViewModels遇重启导航栈异常求助
问题背景
原本使用viewModels()委托无法创建跨Fragment的SharedViewModel,切换为hiltNavGraphViewModels()后实例创建问题解决,但通过Logcat的「Terminate App」操作强制终止应用后重启,抛出异常:
No destination with ID 2131296453 is on the NavController's back stack. The current destination is null
核心原因
hiltNavGraphViewModels()是绑定到指定导航图(NavGraph)的ViewModel委托,它要求NavController的回退栈中存在对应导航图的目的地。当应用被强制终止后,系统默认不会自动恢复导航栈状态,重启时NavController的回退栈为空,找不到绑定的导航图ID,因此触发报错。
解决方案
1. 启用导航栈的自动状态恢复
在配置NavHostFragment时开启状态恢复开关,让系统自动保存和恢复导航栈状态:
class MainActivity : AppCompatActivity() { private lateinit var navController: NavController override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) val navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment // 启用导航状态自动恢复 navHostFragment.restoreStateEnabled = true navController = navHostFragment.navController } }
2. 手动保存/恢复导航栈状态
如果系统自动恢复失效(比如进程被完全销毁),可以手动在Activity的生命周期中保存和恢复导航栈状态:
class MainActivity : AppCompatActivity() { private lateinit var navController: NavController private val NAV_STATE_KEY = "nav_controller_state" override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) val navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment navController = navHostFragment.navController // 从savedInstanceState恢复导航栈状态 savedInstanceState?.getBundle(NAV_STATE_KEY)?.let { navController.restoreState(it) } } override fun onSaveInstanceState(outState: Bundle) { super.onSaveInstanceState(outState) // 保存当前导航栈状态 outState.putBundle(NAV_STATE_KEY, navController.saveState()) } }
3. 安全获取ViewModel(避免空状态报错)
在Fragment中先校验NavController的状态,确保导航图存在后再获取ViewModel,避免直接调用hiltNavGraphViewModels()导致崩溃:
class TargetFragment : Fragment() { // 替换为你的导航图ID private val NAV_GRAPH_ID = R.id.your_shared_nav_graph // 延迟初始化ViewModel,确保导航栈状态正常 private val sharedViewModel: SharedViewModel by lazy { val navController = findNavController() // 检查导航栈中是否存在目标导航图的目的地 val hasValidNavGraph = navController.backStack.any { it.destination.id == NAV_GRAPH_ID } if (navController.currentDestination != null && hasValidNavGraph) { hiltNavGraphViewModels<NAV_GRAPH_ID>() } else { // 导航栈丢失时的降级处理,比如用当前Fragment的ViewModelProvider创建实例 ViewModelProvider(this)[SharedViewModel::class.java] } } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) // 确保NavController就绪后再使用ViewModel findNavController().currentDestination?.let { sharedViewModel.someLiveData.observe(viewLifecycleOwner) { data -> // 业务逻辑处理 } } } }
4. 检查依赖兼容性
确保Navigation和Hilt的版本匹配,避免版本冲突导致的状态恢复异常:
// 导航组件(建议使用稳定版) implementation "androidx.navigation:navigation-fragment-ktx:2.7.7" implementation "androidx.navigation:navigation-ui-ktx:2.7.7" // Hilt相关依赖 implementation "com.google.dagger:hilt-android:2.48" kapt "com.google.dagger:hilt-android-compiler:2.48" implementation "androidx.hilt:hilt-navigation-fragment:1.1.0"
注意事项
- 确认
hiltNavGraphViewModels()指定的ID是导航图(NavGraph)的ID,而非单个目的地(Destination)的ID; - 如果Activity使用了特殊启动模式(如
singleInstance),可能会干扰导航栈恢复,需检查启动模式配置; - 对于需要持久化的ViewModel数据,建议将数据保存到本地存储(如Room、SharedPreferences),避免依赖导航栈状态恢复。
内容的提问来源于stack exchange,提问作者Viewed
相关产品推荐
相关产品推荐

