如何在导航到 Android 中的另一个片段后清除导航堆栈

How to clear navigation Stack after navigating to another fragment in Android

我正在使用 android 中的新 Navigation Architecture Component,但在移动到新片段后我无法清除导航堆栈。

示例: 我在 loginFragment 中,我希望在导航到主页片段时从堆栈中清除该片段,以便用户在按下后退按钮时不会返回到 loginFragment。

我正在使用简单的 NavHostFragment.findNavController(Fragment).navigate(R.id.homeFragment) 进行导航。

当前代码:

mAuth.signInWithCredential(credential)
            .addOnCompleteListener(getActivity(), new OnCompleteListener<AuthResult>() {
                @Override
                public void onComplete(@NonNull Task<AuthResult> task) {
                    if (task.isSuccessful()) {
                        NavHostFragment.findNavController(LoginFragment.this).navigate(R.id.homeFragment);
                    } else {
                        Log.w(TAG, "signInWithCredential:failure", task.getException());
                    }
                }
            });

我尝试使用 NavOptions in the navigate(),但后退按钮仍将我送回 loginFragment

NavOptions.Builder navBuilder = new NavOptions.Builder();
NavOptions navOptions = navBuilder.setPopUpTo(R.id.homeFragment, false).build();   
             NavHostFragment.findNavController(LoginFragment.this).navigate(R.id.homeFragment, null, navOptions);

感谢

,我终于弄明白了

我必须将 .setClearTask(true) 指定为 NavOption。

mAuth.signInWithCredential(credential)
            .addOnCompleteListener(getActivity(), new OnCompleteListener<AuthResult>() {
                @Override
                public void onComplete(@NonNull Task<AuthResult> task) {
                    if (task.isSuccessful()) {
                        Log.d(TAG, "signInWithCredential:success");


                        NavOptions.Builder navBuilder = new NavOptions.Builder();
                        NavOptions navOptions = navBuilder.setClearTask(true).build();
                        NavHostFragment.findNavController(LoginFragment.this).navigate(R.id.homeFragment,null,navOptions);
                    } else {
                        Log.w(TAG, "signInWithCredential:failure", task.getException());

                    }

                }
            });

注意:清除任务已弃用,官方描述为

This method is deprecated. Use setPopUpTo(int, boolean) with the id of the NavController's graph and set inclusive to true.

旧答案

如果您不想在代码中经历所有这些模糊,您可以简单地检查操作属性中 Launch Options 中的 Clear Task

编辑: 自 Android Studio 3.2 Beta 5 起,启动选项中不再显示清除任务 window,但您仍然可以使用它在导航的 XML 代码中,在 action 标签中,通过添加

app:clearTask="true"

首先,将属性 app:popUpTo='your_nav_graph_id'app:popUpToInclusive="true" 添加到操作标签。

<fragment
    android:id="@+id/signInFragment"
    android:name="com.glee.incog2.android.fragment.SignInFragment"
    android:label="fragment_sign_in"
    tools:layout="@layout/fragment_sign_in" >
    <action
        android:id="@+id/action_signInFragment_to_usersFragment"
        app:destination="@id/usersFragment"
        app:launchSingleTop="true"
        app:popUpTo="@+id/main_nav_graph"
        app:popUpToInclusive="true" />
</fragment>

其次,导航到目的地,使用上述操作作为参数。

findNavController(fragment).navigate(
     SignInFragmentDirections.actionSignInFragmentToUserNameFragment())

有关详细信息,请参阅 docs

注意:如果您使用方法 navigate(@IdRes int resId) 进行导航,您将无法获得所需的结果。因此,我使用了方法 navigate(@NonNull NavDirections directions).

我认为您的问题具体涉及如何使用 Pop Behavior / Pop To / app:popUpTo(在 xml 中)

在文档中,
导航前弹出给定目的地。这将从返回堆栈中弹出所有 non-matching 个目的地,直到找到该目的地。

示例(简单的求职应用程序)
我的 start_screen_nav 图表是这样的:

startScreenFragment (start) -> loginFragment -> EmployerMainFragment

                            -> loginFragment -> JobSeekerMainFragment

如果我想导航到 EmployerMainFragment 并弹出所有 包括 startScreenFragment 那么代码将是:

        <action
            android:id="@+id/action_loginFragment_to_employerMainFragment"
            app:destination="@id/employerMainFragment"

            app:popUpTo="@+id/startScreenFragment"
            app:popUpToInclusive="true" />

如果我想导航到 EmployerMainFragment 并弹出所有 排除 startScreenFragment 那么代码将是:

        <action
            android:id="@+id/action_loginFragment_to_employerMainFragment"
            app:destination="@id/employerMainFragment"

            app:popUpTo="@+id/startScreenFragment"/>

如果我想导航到 EmployerMainFragment 并弹出 loginFragment 不是 startScreenFragment 那么代码将是:

        <action
            android:id="@+id/action_loginFragment_to_employerMainFragment"
            app:destination="@id/employerMainFragment"

            app:popUpTo="@+id/loginFragment"
            app:popUpToInclusive="true"/>

        <action
            android:id="@+id/action_loginFragment_to_employerMainFragment"
            app:destination="@id/employerMainFragment"

            app:popUpTo="@+id/startScreenFragment"/>

在我的例子中,我需要在打开新片段之前删除后台堆栈中的所有内容,所以我使用了这段代码

navController.popBackStack(R.id.fragment_apps, true);
navController.navigate(R.id.fragment_company);

第一行删除返回堆栈,直到它到达我的例子中指定的片段,它是主片段,所以它完全删除了所有返回堆栈,当用户在 fragment_company 中单击返回时,他关闭了应用程序。

您可以像这样覆盖底座 activity 的后压:

override fun onBackPressed() {

  val navigationController = nav_host_fragment.findNavController()
  if (navigationController.currentDestination?.id == R.id.firstFragment) {
    finish()
  } else if (navigationController.currentDestination?.id == R.id.secondFragment) {
    // do nothing
  } else {
    super.onBackPressed()
  }

}
    NavController navController 
    =Navigation.findNavController(requireActivity(),          
    R.id.nav_host_fragment);// initialize navcontroller

    if (navController.getCurrentDestination().getId() == 
     R.id.my_current_frag) //for avoid crash
  {
    NavDirections action = 
    DailyInfoSelectorFragmentDirections.actionGoToDestionationFragment();

    //for clear current fragment from stack
    NavOptions options = new 
    NavOptions.Builder().setPopUpTo(R.id.my_current_frag, true).build();
    navController.navigate(action, options);
    }

这是我完成它的方法。

 //here the R.id refer to the fragment one wants to pop back once pressed back from the newly  navigated fragment
 val navOption = NavOptions.Builder().setPopUpTo(R.id.startScorecardFragment, false).build()

//now how to navigate to new fragment
Navigation.findNavController(this, R.id.my_nav_host_fragment)
                    .navigate(R.id.instoredBestPractice, null, navOption)

我努力了一段时间,以防止后退按钮返回到我的开始片段,在我的情况下,这是一条应该只出现一次的介绍消息。

简单的解决方案是创建一个 global action 指向用户应该停留的目的地。您必须正确设置 app:popUpTo="..." - 将其设置为您想要弹出的目的地。就我而言,这是我的介绍信息。同时设置 app:popUpToInclusive="true"

您可以像这样简单地做:

getFragmentManager().popBackStack();

如果你想查看计数,你可以这样做:

getFragmentManager().getBackStackEntryCount()

使用此代码

navController.navigateUp();

然后调用新的片段 android 版本 4.1.2

要在这里添加另一个答案,因为上面的 none 对我有用...我们有多个导航图。

findNavController().navigate(R.id.dashboard_graph,null,NavOptions.Builder().setPopUpTo(findNavController().graph.startDestination, true).build())

这是我能够成功清除全部返回堆栈的唯一方法。 Google 真的需要简化一下。

为了

// Navigation library
    def nav_version = "2.3.5"
    implementation "androidx.navigation:navigation-fragment-ktx:$nav_version"
    implementation "androidx.navigation:navigation-ui-ktx:$nav_version"

这个解决方案对我有用

 
findNavController().popBackStack(R.id.<Current Fragment Id In NavGraph>, true)

 
findNavController().navigate(R.id.< Your Destination Fragment  in NavGraph>)

在我的例子中,我将 Navigation 组件NavigationView(菜单抽屉)一起使用:

1.

mNavController.popBackStack(R.id.ID_OF_FRAGMENT_ROOT_TO_POP, true)
    mNavController.navigate(
      R.id.DESTINATION_ID,
      null,
      NavOptions.Builder()
                .setPopUpTo(R.id.POP_TO_DESTINATION_ID, true)
                .build()
    )

我想在点击侧面菜单抽屉上的注销后清除堆栈! 希望对某人有所帮助!

以上解决方案都不适合我。 花了几个小时后,这是我的解决方案:

注意:我有多个 nav_graphs 并且在不同 nav_graphs 的片段之间切换。

  1. 在 xml 中定义您的操作:
<action
    android:id="@id/your_action_id"
    app:destination="@id/the_fragment_id_you_want_to_navigate_to"
    app:popUpTo="@id/nav_graph_which_contains_destination_fragment"
    app:popUpToInclusive="true" />
  1. 使用上述 Java/Kotlin 代码中的操作进行导航:
findNavController(R.id.your_nav_name)?.apply {
    navigate(R.id.your_action_id)
    backQueue.clear()
}