Get Backstack status using android navigation component
Asked Answered
G

5

20

I want to implement backpress behaviour such that it prompts a confirmation popup when you press back with the backstack empty, otherwise it pops the next fragment in the stack.

I'm trying to get the backstack count, but i always get 0 from both fragment managers

 getSupportFragmentManager().getBackStackEntryCount();
 getFragmentManager().getBackStackEntryCount();

I guess it should work since i checked the google code of fragment navigator and it adds to backstack through the canonical fragment transaction:

FragmentNavigator.java:

 if (initialNavigation || isClearTask) {
        backStackEffect = BACK_STACK_DESTINATION_ADDED;
    } else if (isSingleTopReplacement) {
        // Single Top means we only want one instance on the back stack
        if (mBackStack.size() > 1) {
            // If the Fragment to be replaced is on the FragmentManager's
            // back stack, a simple replace() isn't enough so we
            // remove it from the back stack and put our replacement
            // on the back stack in its place
            mFragmentManager.popBackStack();
            ft.addToBackStack(Integer.toString(destId));
            mIsPendingBackStackOperation = true;
        }
        backStackEffect = BACK_STACK_UNCHANGED;
    } else {
        ft.addToBackStack(Integer.toString(destId));
        mIsPendingBackStackOperation = true;
        backStackEffect = BACK_STACK_DESTINATION_ADDED;
    }
    ft.setReorderingAllowed(true);
    ft.commit();

I didn't find any API to retrieve this information through NavController or Navigator neither.

Thanks

Ghostly answered 24/9, 2018 at 14:40 Comment(0)
S
20

May be help to someone too:

<fragment
    android:id="@+id/YOUR_NAVIGATION_HOST_ID"
    android:name="androidx.navigation.fragment.NavHostFragment"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:defaultNavHost="true"
    app:navGraph="@navigation/YOUR_NAVIGATION_HOST" />
val navHostFragment = supportFragmentManager.findFragmentById(R.id.YOUR_NAVIGATION_HOST_ID)
val backStackEntryCount = navHostFragment?.childFragmentManager?.backStackEntryCount
Spector answered 9/4, 2019 at 7:22 Comment(2)
Please add some more explanation to your code such that others can learn from itLindsley
Not working if I use FragmentContainerViewBailee
A
11

To check the back stack count of a navigation host fragment, you should use childFragmentManager of navHostFragment :

navHostFragment.childFragmentManager.addOnBackStackChangedListener {
            if (navHostFragment.childFragmentManager.backStackEntryCount == 0) {
                // First fragment is open, backstack is empty
            } else {
                // there are fragments in backstack
            }
        }
Abbate answered 11/4, 2020 at 8:51 Comment(0)
S
2

I understand that the answer is late. But may be it will help someone else.

val navHostFragment = supportFragmentManager.findFragmentById(R.id.navDrawerActivity)
val backStackEntryCount = navHostFragment?.childFragmentManager?.fragments?.size
<fragment
    android:id="@+id/navDrawerActivity"
    android:name="androidx.navigation.fragment.NavHostFragment"
    app:navGraph="@navigation/nav_item"
    app:defaultNavHost="true"
/>
Suspect answered 8/11, 2018 at 8:44 Comment(1)
Will you explain why this works? What is so special about navDrawerActivity?Osage
L
2

I also had the same use-case in my app but the scenario was quite complex on my side. Because I made a base fragment and every fragment needs to be inherited from it.Otherwise you need to add the same code in every single fragment. So -

Step 1: Create the BaseFragment and add the

    public class BaseFragment extends Fragment{
    .
    .
    .
    .
     @Override
        public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
            super.onViewCreated(view, savedInstanceState);
    
        
           requireActivity().getOnBackPressedDispatcher().addCallback(getViewLifecycleOwner(),
                    new OnBackPressedCallback(true) {
                        @Override
                        public void handleOnBackPressed() {
                           goBack();
                        }
                    });
    
        }
    private void goBack(){
     NavHostFragment navHostFragment = (NavHostFragment) this.getParentFragment();
            /**If navHostFragment has no fragment in stack that means you reach to the top most fragment on the stack and app exist popup should be shown here.Otherwise just simple pop the immediate fragment from backstack*/
            if (navHostFragment != null &&
                    navHostFragment.getChildFragmentManager().getBackStackEntryCount() == 0) {
                showAppExistPopup(); 
            } else NavHostFragment.findNavController(this).navigateUp();
    
    }
    .
    .
    .
}

Step 2: Just simple inherit your child fragment class by the above base fragment like -

public class MyChildFragment extends BaseFragment 
Longdistance answered 21/12, 2020 at 19:50 Comment(0)
C
0

Hey guys if you wants to remove the backstack then simply go to your nav_graph.xml file and then goto your action tag , write popUpToInclusive="true" , then write popUpTo="@id/splashScreen" ( here pass the id of that screen , which you want to remove , in my case it was splashScreen). check the below code for better understanding..

    <fragment
        android:id="@+id/splashScreen"
        android:name="com.codingwithjks.firebase.SplashScreen"
        android:label="splash_screen"
        tools:layout="@layout/splash_screen" >
        <action
            android:id="@+id/action_splashScreen_to_showUploads"
            app:destination="@id/showUploads"
            app:popUpToInclusive="true"
            app:popUpTo="@id/splashScreen"
            app:enterAnim="@anim/nav_default_pop_enter_anim" />
    </fragment
Ciaphus answered 17/3, 2021 at 12:4 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.