skip to Main Content

I have a single activity app that uses navigation graph and a navigation drawer to go to some of the fragments. Pressing back from each of the fragments usually brings me back to the main fragment, UNLESS I turn the screen off and back on or I put the app in the background. When I resume the app, the up button widget turns back into a hamburger menu, but navigation doesn’t happen. Pressing the android back button doesn’t navigate either, as if the app forgets where to navigate to.

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)
        }
    }
}

Then overriding the onSupportNavigateUp():

override fun onSupportNavigateUp(): Boolean {
    return NavigationUI.navigateUp(navController, appBarConfiguration) || super.onSupportNavigateUp()
}

2

Answers


  1. Chosen as BEST ANSWER

    I found out what was causing it. I was using postponeEnterTransition() to check if the database was empty. If it is, then it should load the first fragment, else the second fragment. The problem was that I was using startPostponedEnterTransition() after the navigation had already left the first fragment, which was causing the navController to misbehave.

    To solve this, I am now starting the enter transition in the first fragment, then hiding it, before navigating to the second fragment. I am also using a splash screen which is being turned off after the navigation is complete.

    In MainActivity:

    val splashScreen = installSplashScreen() 
    splashScreen.setKeepOnScreenCondition { mainVm.keepSplashScreen.value }
    super.onCreate(savedInstanceState) 
    

    In onCreateView of the first fragment:

    postponeEnterTransition() // Wait for data to load before displaying fragment
    mainVm.matchState.observe(viewLifecycleOwner, EventObserver { matchState ->
                when (matchState) {
                    RULES_IDLE -> mainVm.transitionToFragment(this, 0)
                    // Here, if database is not empty, 
                    // start transition right away and hide the view only then navigate
                    // If the transition happens after the navigation has started, 
                    // the navController will have issues returning from the navDrawer fragments.
                    GAME_IN_PROGRESS -> {
                        startPostponedEnterTransition()
                        view?.visibility = GONE
                        navigate(RulesFragmentDirections.gameFrag()
                    }
                    else -> Timber.e("No implementation for state $matchState at this point")
                }
            })
    

    Within the MainViewModel:

    private val _keepSplashScreen = MutableStateFlow(true)
    val keepSplashScreen = _keepSplashScreen.asStateFlow()
    fun transitionToFragment(fragment: Fragment, ms: Long) = viewModelScope.launch {                     
                fragment.startPostponedEnterTransition()
                delay(ms) // Add a delay for the content to fully load before turning off the splash screen
                _keepSplashScreen.value = false
    }
    

    Aside from this, the navController implementation works correctly as per the post above.


  2. If you don’t have below code just add and try again:

        override fun onSupportNavigateUp(): Boolean {
            return NavigationUI.navigateUp(navController, null) || super.onSupportNavigateUp()
        }
    

    Edit: If that doesn’t work then try this:

    layoutAppBarMain.layoutToolbarMain.setNavigationOnClickListener { onBackPressed() }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search