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

You*_*ehi 64 android android-fragments android-architecture-components android-architecture-navigation

我正在使用Android中的新导航架构组件,我在移动到新片段后陷入清理导航堆栈.

示例:我在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());
                    }
                }
            });
Run Code Online (Sandbox Code Playgroud)

我尝试在navigate()中使用NavOptions,但后退按钮仍然将我发送回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);
Run Code Online (Sandbox Code Playgroud)

Sub*_*haw 99

首先,添加属性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>
Run Code Online (Sandbox Code Playgroud)

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

findNavController(fragment).navigate(
     SignInFragmentDirections.actionSignInFragmentToUserNameFragment())
Run Code Online (Sandbox Code Playgroud)

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

  • 我认为这个答案的关键在于“popUpTo”(它删除了当前片段和你传递给这个参数的 id 的第一次出现之间的所有片段)被设置为导航图本身的 *id*。有效地完全清除 backstack。仅添加此评论是因为我还没有看到它完全像这样解释,而这正是我正在寻找的。+1! (18认同)
  • 也可以像使用`findNavController(fragment).navigate(R.id.action_signInFragment_to_usersFragment)那样使用动作的id. (6认同)
  • **注意**:如果您不包括safe-args gradle,则不会生成“ Directions”类。有关更多信息,请访问[here](https://medium.com/google-developer-experts/android-navigation-components-part-3-19554ec9ae83。) (3认同)
  • 最佳答案是 clearTask 现在已在新版本的 Android 导航组件中弃用! (2认同)
  • 任何人都调查过为什么“如果您使用方法导航(@IdRes int resId)进行导航,您将不会获得所需的结果。” ? (2认同)
  • 如果我使用导航架构组件从片段导航到活动,如何清除后台堆栈? (2认同)

Ton*_*ony 26

要在这里添加另一个答案,因为上述内容都不适合我......我们有多个导航图。

findNavController().navigate(R.id.dashboard_graph,null,NavOptions.Builder().setPopUpTo(findNavController().graph.startDestination, true).build())
Run Code Online (Sandbox Code Playgroud)

这是我能够成功清除完整后堆栈的唯一方法。谷歌确实需要让这一切变得更简单。


Mel*_*Mel 13

注意:不推荐使用清除任务,官方说明是

不推荐使用此方法.将setPopUpTo(int,boolean)与NavController的图形的id一起使用,并将inclusive设置为true.

老答案

如果您不想通过代码中的所有模糊,您只需签Clear Task入操作Launch Options的属性即可.

启动选项

编辑:从Android Studio 3.2 Beta 5开始,"清除任务"在"启动选项"窗口中不再可见,但您仍可以在导航的XML代码中使用它,在操作标记中添加

app:clearTask="true"
Run Code Online (Sandbox Code Playgroud)


ema*_*esh 9

    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);
    }
Run Code Online (Sandbox Code Playgroud)


小智 7

我认为您的问题特别涉及如何使用“流行为” /“流行为” / app:popUpTo(在xml中)

在文档中,
导航之前弹出到给定的目的地。这将从后堆栈中弹出所有不匹配的目标,直到找到该目标为止。

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

startScreenFragment (start) -> loginFragment -> EmployerMainFragment

                            -> loginFragment -> JobSeekerMainFragment
Run Code Online (Sandbox Code Playgroud)

如果我想导航到EmployerMainFragment并弹出所有包含 startScreenFragment的代码,则代码为:

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

            app:popUpTo="@+id/startScreenFragment"
            app:popUpToInclusive="true" />
Run Code Online (Sandbox Code Playgroud)

如果我要导航到EmployerMainFragment并弹出所有排除项, startScreenFragment则代码为:

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

            app:popUpTo="@+id/startScreenFragment"/>
Run Code Online (Sandbox Code Playgroud)

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

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

            app:popUpTo="@+id/loginFragment"
            app:popUpToInclusive="true"/>
Run Code Online (Sandbox Code Playgroud)

要么

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

            app:popUpTo="@+id/startScreenFragment"/>
Run Code Online (Sandbox Code Playgroud)

  • 如何以编程方式而不是 XML 来完成此操作? (5认同)

小智 7

在我的情况下,我需要在打开新片段之前先移除背面堆栈中的所有内容,以便使用此代码

navController.popBackStack(R.id.fragment_apps, true);
navController.navigate(R.id.fragment_company);
Run Code Online (Sandbox Code Playgroud)

第一行删除后堆栈,直到到达我所指定的片段为止,这是家庭片段,因此它将完全删除所有后堆栈,当用户在fragment_company中单击时,他关闭了该应用程序。

  • 什么是“fragment_apps”? (6认同)
  • 当前片段。就像如果你在fragmentOne上并且想要去fragmentTwo你也需要使用navController.popBackStack(R.id.fragmentOne, true); navController.navigate(R.id.fragmentTwo); (3认同)
  • 这是唯一对我有用的东西(Navigation v2.3.5)。 (2认同)

Abd*_*air 7

这是我如何完成它。

 //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)
Run Code Online (Sandbox Code Playgroud)

  • 根据[文档](https://developer.android.com/reference/androidx/navigation/NavOptions.Builder#setPopUpTo(int,%20boolean)) `inclusive boolean: true 也从后堆栈中弹出给定的目的地`因此,我将包含设置为 false,因为我不想从堆栈中弹出当前片段。 (3认同)

小智 7

使用此代码

navController.navigateUp();
Run Code Online (Sandbox Code Playgroud)

然后调用新的 Fragment android 版本 4.1.2


sha*_*sar 7

为了

// Navigation library
    def nav_version = "2.3.5"
    implementation "androidx.navigation:navigation-fragment-ktx:$nav_version"
    implementation "androidx.navigation:navigation-ui-ktx:$nav_version"
Run Code Online (Sandbox Code Playgroud)

这个解决方案对我有用

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

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

Run Code Online (Sandbox Code Playgroud)


小智 7

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

1.

mNavController.popBackStack(R.id.ID_OF_FRAGMENT_ROOT_TO_POP, true)
Run Code Online (Sandbox Code Playgroud)
    mNavController.navigate(
      R.id.DESTINATION_ID,
      null,
      NavOptions.Builder()
                .setPopUpTo(R.id.POP_TO_DESTINATION_ID, true)
                .build()
    )
Run Code Online (Sandbox Code Playgroud)

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


You*_*ehi 6

我终于弄清楚了,这要归功于如何使用新的导航体系结构组件对某些片段禁用导航中的UP?

我必须将.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());

                    }

                }
            });
Run Code Online (Sandbox Code Playgroud)

  • 是的,不赞成使用“ setClearTask”,但您可以使用:`val navOptions = NavOptions.Builder()。setPopUpTo(R.id.my_current_frag,true).build()``findNavController()。navigate(R.id.my_next_frag, null,navOptions)` (9认同)
  • 只是要注意setClearTask函数已被弃用 (8认同)
  • 很高兴看到您能够实现我对使用`navigate(int resId,Bundle args,NavOptions navOptions)`和`NavOptions`的建议。 (2认同)
  • @PabloReyes 这是正确的答案。只需指定最后要删除的片段: 假设您有以下堆栈: Fragment_1 Fragment_2 Fragment_3 您现在位于 Fragment_3 上,想要导航到 Fragment_4 并清除所有其他片段。只需在导航 xml 中指定: app:popUpTo="@id/Fragment_1" app:popUpToInclusive="true" (2认同)