Navigation 2.3.5 Activity重建时getGraph()报错及状态恢复失效问题
问题根因
这个异常是Navigation 2.3.5版本的典型场景问题,触发逻辑非常明确:
- Activity被系统回收重建、或开启「不保留活动」选项时,
super.onCreate()执行阶段不会自动完成NavController的导航图初始化,此时直接调用getGraph()就会抛出You must call setGraph() before calling getGraph()异常。 - 你手动实现的状态保存恢复逻辑无效,核心原因是顺序错误:
restoreState()仅能恢复回退栈状态,必须先执行setGraph()给NavController绑定导航图,才能调用restoreState()恢复栈数据,直接跳过setGraph步骤调用restoreState没有任何作用。 - Navigation 2.2.0及以上版本已经内置了NavHostFragment的状态自动保存恢复逻辑,你手动在
onSaveInstanceState里存nav_state的操作是多余的,反而可能和组件内置逻辑产生冲突。
修复步骤
按以下顺序调整代码即可解决:
- 移除你手动写的导航状态保存、恢复代码,包括
onSaveInstanceState里的putBundle("nav_state")逻辑,以及onCreate里的restoreState()调用,交给组件自动处理即可。 - 调整NavController和ViewModel的初始化时机,必须保证在访问
graph.id之前,NavController已经完成导航图绑定,参考代码如下:
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // 必须先加载布局,NavHostFragment是在布局inflate阶段完成绑定的 setContentView(R.layout.activity_main) val navController = findNavController(R.id.nav_host_fragment) // 重建场景下先判断graph是否已初始化,未初始化则主动绑定导航图 if (navController.currentDestination == null) { navController.setGraph(R.navigation.你的对应导航图ID) } // 此时graph已经完成初始化,再初始化作用域ViewModel不会报错 val myViewModel: MyViewModel by navGraphViewModels(navController.graph.id) { defaultViewModelProviderFactory } }
注意事项
- 不要将
navGraphViewModels的初始化写在Activity的成员变量赋值位置,成员变量初始化早于onCreate生命周期执行,此时NavController还未完成绑定,必然触发异常。 - 如果项目存在多个导航图,不要在Activity层级统一初始化所有navGraph作用域的ViewModel,建议在对应导航图内的起始Fragment的
onViewCreated生命周期里初始化对应作用域的ViewModel,此时NavController的导航图一定处于已初始化状态,不会出现时序问题。 - 2.3.5版本不要在
setContentView()调用之前执行findNavController(),此时拿到的NavController实例未完成和NavHostFragment的关联,所有graph相关操作都会失效。
内容的提问来源于stack exchange,提问作者aherman
相关产品推荐
相关产品推荐

