Why Does Navigation Not Work in the Navigation Drawer Activity Template with Version 2.4.1

Why does navigation not work in the Navigation Drawer Activity template with version 2.4.1?

tl/dr: You should be following the Tie destinations to menu items documentation and using NavigationUI.onNavDestinationSelected() to get the right behavior:

@Override
public boolean onOptionsItemSelected(MenuItem item) {
NavController navController = Navigation.findNavController(this,
R.id.nav_host_fragment_content_main);

// By calling onNavDestinationSelected(), you always get the right behavior
return NavigationUI.onNavDestinationSelected(item, navController)
|| super.onOptionsItemSelected(item);
}

Why

Navigation 2.4 uses multiple back stacks associated with each element in your NavigationView as per the Add a navigation drawer guide:

Starting in Navigation 2.4.0-alpha01, the state of each menu item is saved and restored when you use setupWithNavController.

That means that the 'Home' screen has a back stack associated with it that is restored when you tap on that icon, same for Gallery, Slideshow, and Settings. This is how the state is saved for that item.

This means that each tap on the items in your drawer isn't just navigating to that screen, but is swapping in the entire back stack associated with that item - everything that you've navigated to from that first screen.

So when you call Navigation.findNavController(this, R.id.nav_host_fragment_content_main).navigate(R.id.nav_settings);, you aren't doing the same thing as selecting the Settings item in your drawer - you're just adding the Settings screen to the 'Home' screen's back stack. This is why tapping on the Home icon doesn't do anything - you're already on the 'Home' screen's back stack.

What you actually want to do is swap to the entirely separate back stack associated with the nav_settings item. This would separate the nav_settings back stack from the Home back stack, thus ensuring that tapping the Home icon takes you back to the Home screen's back stack.

This is exactly what the NavigationUI.onNavDestinationSelected() API does (as that's exactly what the setupWithNavController API uses), so you can simply use that directly in your onOptionsItemSelected().

However, if you want to manually call navigate() (which, by the way, means you aren't getting the cross fade animation that you get by default when using onNavDestinationSelected), you can add the saving state flags to your navigate call by applying NavOptions programmatically:

@Override
public boolean onOptionsItemSelected(MenuItem item) {
Bundle bundle =new Bundle();
switch (item.getItemId()) {
case R.id.action_settings:
{
// Manually build the NavOptions that manually do
// what NavigationUI.onNavDestinationSelected does for you
NavOptions navOptions = new NavOptions.Builder()
.setPopUpTo(R.id.nav_home, false, true)
.setRestoreState(true)
.build();

NavController navController = Navigation.findNavController(this,
R.id.nav_host_fragment_content_main);

navController.navigate(R.id.nav_settings, navOptions);
return true;
}

default:
return super.onOptionsItemSelected(item);
}
}

Note that the setupWithNavController API relies on the nested graph of the current destination to determine which item is selected - the expectation is that all destinations in the 'Home' tab are part of the 'Home' navigation graph. So because you've swapped to the nav_settings, setupWithNavController assumes you've swapped to that back stack. Since you haven't actually done that, that's why your selected item gets out of sync with which back stack you are on.

Fragment navigation and menu. How to remove latest fragment? Check description

Found the core issue for this problem. The detailed explanation lies in this answer.

For the moment, Is solved it by downgrading the the fragment dependency from 'androidx.navigation:navigation-fragment-ktx:2.4.1'
to
'androidx.navigation:navigation-fragment-ktx:2.3.5'
and now everything works fine.

Bottom navigation bar malfunctions when navigating from a fragment

As @ianhanniballake mentioned in a comment, a similar question was posted here

What I ended up doing was replacing

val action = MainFragmentDirections.actionMainFragmentToReportsFragment()
navController.navigate(action)

with

val item = mainBottomNavigationView.menu.findItem(R.id.reportsFragment)
NavigationUI.onNavDestinationSelected(item, navController)

So basically I used the NavigationUI API to navigate so that it correctly tracks the back stack. The same NavigationUI API is being used by the BottomNavigationView internally



Related Topics



Leave a reply



Submit