使用Navigation Drawer与Navigation Component实现应用重启后恢复上次打开的Fragment
实现方案选择结论
两种方案均可正常实现需求,优先选择「binding.navView.setNavigationItemSelectedListener设置选中监听 + 手动触发选中」的组合方案,比直接调用Navigation.findNavController().navigate()更稳妥:直接调用navigate()需要额外手动同步侧边栏菜单项的选中高亮状态,还要额外处理回退栈逻辑,很容易出现页面跳转正确但侧边栏选中状态不匹配、按返回键回到首页的问题。
完整实现步骤
第一步:修正DataStore写入时机,保证所有页面切换场景都能正确存储上次访问的目的地
不要只在侧边栏点击监听里存目的地ID,给NavController注册全局OnDestinationChangedListener,不管是侧边栏跳转、按钮跳转、通知跳转触发的页面切换都会触发监听,不会漏存:navController.addOnDestinationChangedListener { _, destination, _ -> // 存destination.id到DataStore,这个ID和导航图、侧边栏menu的item ID完全一致 viewModel.saveLastDestinationId(destination.id) }第二步:应用重启时的恢复逻辑,放在MainActivity
onCreate方法中,NavController初始化完成后执行
注意DataStore是异步读写,用生命周期协程包裹读取逻辑,避免阻塞主线程,同时要校验读取到的ID合法性:lifecycleScope.launchWhenStarted { // 读取上次存的ID,传入默认值(导航图的起始页ID,第一次启动没有存储记录时用) val lastDestId = viewModel.getLastDestinationId(navController.graph.startDestinationId) // 校验ID是否在导航图中存在,避免存了无效ID导致崩溃 if (navController.graph.contains(lastDestId)) { // 直接设置侧边栏选中项,自动触发你已配置的选中监听跳转,同时同步高亮状态 binding.navView.setCheckedItem(lastDestId) // 如果你要选直接调用navigate的方案,记得配置NavOptions清理回退栈,避免按返回键回到首页 /* navController.navigate( lastDestId, null, NavOptions.Builder() .setPopUpTo(navController.graph.startDestinationId, true) .build() ) */ } }第三步:前置校验要求
导航图中每个Fragment的android:id必须和侧边栏menu对应item的android:id完全一致,这是Navigation组件原生适配侧边栏的基础要求,ID不匹配会导致跳转/选中失效。
常见DataStore不生效排查点
- 存储时机不对,只在侧边栏点击时存,其他跳转场景没更新存储值
- 恢复逻辑执行太早,NavController还没初始化完成就调用跳转
- 协程作用域不对,读DataStore的协程被提前取消,没拿到存储值就执行了跳转逻辑
内容的提问来源于stack exchange,提问作者Dr Mido
相关产品推荐
相关产品推荐

