使用Android Navigation组件获取返回栈状态

20

我希望实现后退行为,这样当你按下后退键并且回退栈为空时,它会提示确认弹窗,否则它会弹出栈中的下一个片段。

我正在尝试获取回退栈的计数,但是无论从哪个片段管理器中获取都始终得到0。

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

我想这应该可行,因为我检查了Fragment Navigator的Google代码,并且它通过规范的Fragment事务添加到后退堆栈中:
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();

我在NavController或Navigator中没有找到任何检索此信息的API。谢谢。
5个回答

20

可能对某些人有帮助:

<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

2
请在您的代码中添加更多的解释,以便其他人可以从中学习。 - Nico Haase
2
如果我使用FragmentContainerView就无法工作。 - Alif Hasnain

11

要检查导航宿主片段的返回栈计数,您应该使用navHostFragment的childFragmentManager:

navHostFragment.childFragmentManager.addOnBackStackChangedListener {
            if (navHostFragment.childFragmentManager.backStackEntryCount == 0) {
                // First fragment is open, backstack is empty
            } else {
                // there are fragments in backstack
            }
        }

2

我知道回答晚了,但也许它可以帮助其他人。

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"
/>

你能解释一下为什么这个有效吗?navDrawerActivity有什么特别之处吗? - tir38

2
我也在我的应用程序中有同样的用例,但是情况在我的一面相当复杂。因为我制作了一个基础片段,并且每个片段都需要从它那里继承。否则,您需要在每个单独的片段中添加相同的代码。所以 - 步骤1:创建BaseFragment并添加
    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();
    
    }
    .
    .
    .
}

步骤二:只需将您的子片段类继承上述基本片段即可,如下所示 -

public class MyChildFragment extends BaseFragment 

0
嘿,大家好,如果你想删除后退栈,那么只需进入你的 nav_graph.xml 文件,然后进入你的 action 标签,写上 popUpToInclusive="true",然后写上 popUpTo="@id/splashScreen"(在这里输入要删除的屏幕的 id,在我的情况下是 splashScreen)。查看下面的代码以获得更好的理解。
    <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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接