求助:Android Navigation Component+BottomNavigationBar复用Fragment实例
核心原因
每次切换标签时直接调用navigate(R.id.xxx_navigation)会在回退栈中添加新的导航图实例,导致旧实例留存、无法复用。
解决方案
1. 自定义BottomNavigation标签点击逻辑
放弃默认的setupWithNavController,手动实现标签点击监听,通过导航选项确保复用已有实例:
bottomNavigationView.setOnItemSelectedListener { menuItem -> val navController = findNavController(R.id.nav_host_fragment) val destinationId = when (menuItem.itemId) { R.id.dashboard_menu -> R.id.dashboard_navigation R.id.documents_menu -> R.id.documents_navigation R.id.templates_menu -> R.id.templates_navigation R.id.settings_menu -> R.id.settings_navigation else -> return@setOnItemSelectedListener false } // 当前已在目标导航图时,直接返回不跳转 if (navController.currentDestination?.id == destinationId) { return@setOnItemSelectedListener true } // 配置导航选项:弹出到主导航图,恢复之前的状态 val navOptions = NavOptions.Builder() .setPopUpTo(R.id.main_nav_graph, false) .setRestoreState(true) .build() navController.navigate(destinationId, null, navOptions) true }
2. 优化登录后的跳转逻辑
登录成功跳转Dashboard时,清理回退栈中的登录相关页面,避免残留:
val navOptions = NavOptions.Builder() .setPopUpTo(R.id.login_navigation, true) // 弹出登录导航图(包含自身) .build() findNavController().navigate(R.id.dashboard_navigation, null, navOptions)
3. 绑定ViewModel到子导航图
若需ViewModel在标签切换时保留状态,使用navGraphViewModels绑定到对应子导航图,而非默认的viewModels():
// 在DashboardFragment中 private val viewModel: DashboardViewModel by navGraphViewModels(R.id.dashboard_navigation)
原理说明
setPopUpTo(R.id.main_nav_graph, false):弹出回退栈中主导航图之上的所有页面,避免栈内堆积多个标签页实例。setRestoreState(true):恢复目标导航图的历史状态(包括Fragment实例和ViewModel),实现复用效果。- 提前判断当前导航状态,避免无意义的重复跳转。
内容的提问来源于stack exchange,提问作者Awais Abbas
相关产品推荐
相关产品推荐

