屏幕熄灭或后台恢复后,Fragment导航抽屉无法返回主Fragment
导航状态丢失问题:后台恢复后返回键/汉堡菜单失效
我开发了一个单Activity应用,用Navigation Graph和Navigation Drawer切换Fragment。正常情况下从各Fragment按返回键能回到主Fragment,但屏幕熄灭再点亮或应用进入后台后恢复时,返回按钮变成汉堡菜单,点击没反应,Android返回键也无法导航,就像应用忘了导航路径一样。
原实现代码
导航初始化代码
val navController = (supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment).navController setSupportActionBar(layoutAppBarMain.layoutToolbarMain) NavigationUI.setupActionBarWithNavController(this@MainActivity, navController, mainDrawerLayout) appBarConfiguration = AppBarConfiguration(navController.graph, mainDrawerLayout) NavigationUI.setupWithNavController(mainActivityNavView, navController) supportActionBar?.setDisplayShowTitleEnabled(false) navController.addOnDestinationChangedListener { _: NavController, nd: NavDestination, _: Bundle? -> when (nd.id) { R.id.playFragment -> mainDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED) R.id.navRulesFragment, R.id.navImproveFragment, R.id.navAboutFragment, R.id.navDonateFragment -> mainDrawerLayout.setDrawerLockMode( DrawerLayout.LOCK_MODE_LOCKED_CLOSED) else -> { binding.layoutAppBarMain.layoutToolbarMain.navigationIcon = null mainDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED) } } }
导航向上方法重写
override fun onSupportNavigateUp(): Boolean { return NavigationUI.navigateUp(navController, appBarConfiguration) || super.onSupportNavigateUp() }
问题原因
核心问题出在应用后台恢复时,NavController实例可能重新创建,但原有引用未更新,同时AppBarConfiguration与导航栈的关联未同步。另外手动设置navigationIcon = null的操作,在恢复时未重新触发,导致UI状态与实际导航栈不匹配。
修复方案
1. 调整导航初始化逻辑,抽离为单独方法
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityMainBinding.inflate(layoutInflater) setContentView(binding.root) setupNavigation() } private fun setupNavigation() { val navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment val navController = navHostFragment.navController setSupportActionBar(binding.layoutAppBarMain.layoutToolbarMain) supportActionBar?.setDisplayShowTitleEnabled(false) // 明确指定顶层目的地(仅主Fragment显示汉堡菜单) appBarConfiguration = AppBarConfiguration( setOf(R.id.playFragment), binding.mainDrawerLayout ) NavigationUI.setupActionBarWithNavController(this, navController, appBarConfiguration) NavigationUI.setupWithNavController(binding.mainActivityNavView, navController) navController.addOnDestinationChangedListener { _, nd, _ -> when (nd.id) { R.id.playFragment -> { binding.mainDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED) } R.id.navRulesFragment, R.id.navImproveFragment, R.id.navAboutFragment, R.id.navDonateFragment -> { binding.mainDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED) } else -> { binding.mainDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED) } } } }
2. 在onResume中重新同步导航状态
override fun onResume() { super.onResume() val navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment val navController = navHostFragment.navController // 后台恢复后重新关联ActionBar与最新的NavController NavigationUI.setupActionBarWithNavController(this, navController, appBarConfiguration) }
3. 修改onSupportNavigateUp,实时获取最新NavController
override fun onSupportNavigateUp(): Boolean { val navController = (supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment).navController return NavigationUI.navigateUp(navController, appBarConfiguration) || super.onSupportNavigateUp() }
关键修改说明
- 抽离导航初始化方法,便于重复调用同步状态
- 明确配置AppBarConfiguration的顶层目的地,让NavigationUI自动管理汉堡/返回图标,无需手动修改
navigationIcon - onResume中重新同步ActionBar与NavController,解决后台恢复时实例更新导致的关联失效
- onSupportNavigateUp中实时获取NavController,避免持有旧引用
内容的提问来源于stack exchange,提问作者Victor Cocuz
相关产品推荐
相关产品推荐

