17

So I have a scenario in which I have 5 fragments attached with bottom navigation.

1. Home 2. Inbox 3. Search 4. Notification 5. Profile

So I have another fragment called (BarcodeDetail) to which I navigate from Home Fragment.

(Home -> BarcodeDetail)

Now from BarcodeDetail I navigate to Search Fragment

(BarcodeDetail -> Search)

But now if I select Home Fragment from BottomNavigationView It did not go to Home Fragment.

Rather than it selects the same current fragment that is Search Fragment.

(The log print the name of Search Fragment)

navController.addOnDestinationChangedListener((controller, destination, bundle) -> {

            Timber.d("Destination -> %s", destination.getDisplayName());
});

private void setupBottomNavigation() {

        NavHostFragment navHostFragment = (NavHostFragment)
                getSupportFragmentManager().findFragmentById
                        (R.id.fragment_container_view);

        if (navHostFragment != null) {

            navController = navHostFragment
                    .getNavController();

            NavigationUI.setupWithNavController(
                    binding.bottomNavigation, navController);

            initDestinationListener();

        }
    }

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">

    <item
        android:id="@+id/sellerHomeFragment"
        android:icon="@drawable/ic_home"
        android:title="@string/home_text" />

    <item
        android:id="@+id/inboxFragment"
        android:icon="@drawable/ic_chat"
        android:title="@string/chats_text" />

    <item
        android:id="@+id/searchFragment"
        android:icon="@drawable/ic_search"
        android:title="@string/search_text" />

    <item
        android:id="@+id/sellerAlertFragment"
        android:icon="@drawable/ic_notification"
        android:title="@string/notifications_text" />

    <item
        android:id="@+id/sellerProfileFragment"
        android:icon="@drawable/ic_profile"
        android:title="@string/profile_text" />

</menu>

Please let me know if you need more information. Thanks

Malik Bilal
  • 869
  • 8
  • 25

5 Answers5

17

The navigation component lib enables multiple backstack support by default since the version 2.4.0, which has been also thoroughly demonstrated in this blog.

According to your sample code, your five top level fragments in your bottom sheet nav would now have their own backstack, the problem arises if you want to navigate from one of the top level fragments to another, like in your case (Home -> ... -> Search).

The reason why you cannot go back to Home is because you have never left Home's backstack and now Search is on top of it, i.e. the navigation component thinks that you're already on the correct fragment.

I would suggest to go through the navigation lib's recent changes first, rather then trying to quick fix as this is quite a behavior change and it could also affect other parts of your app's navigation.

Technically speaking, the way how the multiple back stacks for the bottom nav works is that every time you select a different bottom nav option, the implementation of onNavDestinationSelected(item: MenuItem, navController: NavController) would pop & save the state of all the fragments from the current top level fragment and then navigate to the other top level fragment by restoring it's state.

So, in order to "switch from one backstack to another" like in your case when you navigate from BarcodeDetail to Search, you need to adapt your current actions by at least these two options:

app:popUpTo="@id/id_of_home"
app:popUpToSaveState="true"

(where id_of_home is should be the id of Home and where I assume that this is the action with destination to Search).

With these two lines, you would pop & save the state of Home -> BarcodeDetail and navigate to Search, if you now would navigate back to Home via the bottom nav option, then you would restore the state and your navigation should be basically possible.

However, please note that you might need another flags like app:restoreState="true" and/or app:popUpToInclusive="true" depending on what you want achieve.

mathew11
  • 3,382
  • 3
  • 25
  • 32
  • Hi. Do you have any sample code for this bro ? I'm looking for a solution for this. – Thân Hoàng Apr 27 '22 at 10:09
  • 1
    This is a really good explanation and the actual reason of the problem after the migrating to the new Navigation version ! With the multiple back stacks introduced, we need to specify our intentions with `app:popUpTo` or `app:popUpToSaveState` in actions. – Mert Kılıç Apr 28 '22 at 11:24
  • Works for me, thx. @ThânHoàng, just add those 2 lines to your action element in your navigation.xml. – Dino Tw Jul 06 '22 at 05:47
5

First clear the backstack by using this line of code

     navController.popBackStack();

After that do navigate to your fragment by using this line of code

navController.navigate(R.id.your_fragment_id);

From this you will be able to navigate in bottom navigation without any issue.

AFAQ AWAN
  • 51
  • 1
  • 2
2

I got the same problem in Navigation component 2.4.0, switching back to 2.3.5 works.

But after some testing I got it to work with 2.4.0 also if I add a listerner to BottomNavigationView and handle the navigation my self in addition to NavigationUI.setupWithNavController(..).

bottomNavigationView.setOnItemSelectedListener(item -> {
   //logic like navController.popBackStack(R.id.homeFragment, false) and navController.navigate(item.getItemId(), null, options)
   return true;
});
Per.J
  • 1,229
  • 8
  • 12
2

To Disable BackStack use the below Hacky Solution,

binding.bottomNavigationView.setOnItemSelectedListener {
            NavigationUI.onNavDestinationSelected(it,findNavController(R.id.mainNavHost))
            findNavController(R.id.mainNavHost).popBackStack(it.itemId, inclusive = false)
            true
        }

Tested with

implementation 'androidx.navigation:navigation-fragment-ktx:2.4.0'
implementation 'androidx.navigation:navigation-ui-ktx:2.4.0'
Kintan Patel
  • 1,230
  • 8
  • 15
  • You can get the same results by using `NavigationUI.onNavDestinationSelected(item, controller, saveState = false)` – aPaul Jun 15 '23 at 17:32
1

i am also faced same problem just add app:popUpTo="@id/navigationHome" in your action tag

  <fragment
    android:id="@+id/navigationHome"
    android:name="com.mymedisage.medisageapp.ui.home.HomeFragment"
    android:label="@string/title_home"
    tools:layout="@layout/fragment_home_new" >
    <action
        android:id="@+id/action_homeFragment_to_communityFragment"
        app:destination="@id/navigationCommunity"
        app:popUpTo="@id/navigationHome"
        app:popUpToSaveState="true"
        />
Swapnil
  • 121
  • 7