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

时间:2018-05-24 17:10:24

标签: android android-fragments android-architecture-components android-architecture-navigation

我在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中的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);

14 个答案:

答案 0 :(得分:46)

首先,将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)

答案 1 :(得分:10)

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

  

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

旧答案

如果您不想浏览代码中的所有模糊内容,只需在Clear Task中查看操作属性中的Launch Options即可。

Launch Options

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

app:clearTask="true"

答案 2 :(得分:5)

使用此代码

navController.navigateUp();

然后调用新的Fragment 安卓版本4.1.2

答案 3 :(得分:3)

感谢How to disable UP in Navigation for some fragment with the new Navigation Architecture Component?

,我终于明白了

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

                    }

                }
            });

答案 4 :(得分:2)

    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);
    }

答案 5 :(得分:2)

这是我要完成的方式。

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

答案 6 :(得分:1)

就我而言,我需要在打开新片段之前先移除后堆栈中的所有内容,以便使用此代码

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

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

答案 7 :(得分:1)

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

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

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

答案 8 :(得分:0)

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

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

示例(简单的求职应用)
我的 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"/>

OR

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

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

答案 9 :(得分:0)

您可以像这样覆盖基本活动的后退键:

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()
  }

}

答案 10 :(得分:0)

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

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

答案 11 :(得分:-1)

注意:这可能与实际问题无关。

如果需要单个片段实例来维护导航,则此方法将很有用。

// imports
import androidx.navigation.navOptions

// navigate to fragment
navController.navigate(
    R.id.nav_single_instance_fragment, 
    null,
    navOptions {
        popUpTo = R.id.nav_single_instance_fragment
        launchSingleTop = true
    }
)

在这里,navOptions是DSL,需要导入。 在回答此问题时,我正在使用以下 Navigation UI 的gradle版本。

def nav_version = "2.2.0"

// For Java project
implementation "androidx.navigation:navigation-ui:$nav_version"
implementation "androidx.navigation:navigation-fragment:$nav_version"

// For Kotlin project
implementation "androidx.navigation:navigation-ui-ktx:$nav_version"
implementation "androidx.navigation:navigation-fragment-ktx:$nav_version"

答案 12 :(得分:-1)

我可以通过一个小例子对此进行解释。我有两个片段雇员列表和删除雇员。在删除员工中,我有两个单击事件,分别是取消和删除。如果我单击“取消”,则只需返回到“员工列表”屏幕,如果我单击“删除”,则我想清除以前的所有后退堆栈,然后转到“员工列表”屏幕。

要转到上一个屏幕:

<action
        android:id="@+id/action_deleteEmployeeFragment_to_employeesListFragment2"
        app:destination="@id/employeesListFragment"/>


    btn_cancel.setOnClickListener {
                it.findNavController().popBackStack()
            }

要清除所有以前的后退堆栈并转到新屏幕:

<action
        android:id="@+id/action_deleteEmployeeFragment_to_employeesListFragment2"
        app:destination="@id/employeesListFragment"
        app:popUpTo="@id/employeesListFragment"
        app:popUpToInclusive="true"
        app:launchSingleTop="true" />


 btn_submit.setOnClickListener {
                   it.findNavController().navigate(DeleteEmployeeFragmentDirections.actionDeleteEmployeeFragmentToEmployeesListFragment2())
        }

更多参考:Jetpack Navigation Example

答案 13 :(得分:-2)

您可以执行以下操作:

getFragmentManager().popBackStack();

如果要检查计数,可以执行以下操作:

getFragmentManager().getBackStackEntryCount()