How to clear navigation Stack after navigating to another fragment in Android
我在android中使用新的Navigation Architecture Component,并且在移动到新片段后仍无法清除导航堆栈。
例:
我在loginFragment中,当我导航到home片段时,我希望从堆栈中清除此片段,以便当用户按下后退按钮时,用户不会返回到loginFragment。
我正在使用一个简单的NavHostFragment.findNavController(Fragment).navigate(R.id.homeFragment)进行导航。
当前代码:
1 2 3 4 5 6 7 8 9 10 11 | 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()); } } }); |
我尝试在navigation()中使用NavOptions,但后退按钮仍将我发送回loginFragment
1 2 3 | 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); |
首先,将
1 2 3 4 5 6 7 8 9 10 11 12 | <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> |
其次,使用上述动作作为参数导航到目的地。
1 2 | findNavController(fragment).navigate( SignInFragmentDirections.actionSignInFragmentToUserNameFragment()) |
有关更多信息,请参阅文档。
注意:如果使用方法
我认为您的问题特别涉及如何使用"流行为" /"流行为" / app:popUpTo(在xml中)
在文档中
导航之前,弹出到给定的目的地。这将从后堆栈中弹出所有不匹配的目标,直到找到该目标为止。
示例(简单的求职应用)
我的start_screen_nav图是这样的:
1 2 3 | startScreenFragment (start) -> loginFragment -> EmployerMainFragment -> loginFragment -> JobSeekerMainFragment |
如果我要导航到
1 2 3 4 5 6 | <action android:id="@+id/action_loginFragment_to_employerMainFragment" app:destination="@id/employerMainFragment" app:popUpTo="@+id/startScreenFragment" app:popUpToInclusive="true" /> |
如果我要导航到
1 2 3 4 5 | <action android:id="@+id/action_loginFragment_to_employerMainFragment" app:destination="@id/employerMainFragment" app:popUpTo="@+id/startScreenFragment"/> |
如果我要导航到
1 2 3 4 5 6 | <action android:id="@+id/action_loginFragment_to_employerMainFragment" app:destination="@id/employerMainFragment" app:popUpTo="@+id/loginFragment" app:popUpToInclusive="true"/> |
要么
1 2 3 4 5 | <action android:id="@+id/action_loginFragment_to_employerMainFragment" app:destination="@id/employerMainFragment" app:popUpTo="@+id/startScreenFragment"/> |
在我的情况下,我需要在打开新片段之前先移除背面堆栈中的所有内容,以便使用此代码
1 2 | navController.popBackStack(R.id.fragment_apps, true); navController.navigate(R.id.fragment_company); |
第一行删除后堆栈,直到到达我所指定的片段为止,这是家庭片段,因此它完全删除了所有后堆栈,当用户在fragment_company中单击时,他关闭了该应用程序。
注意:清除任务已弃用,正式说明为
This method is deprecated. Use setPopUpTo(int, boolean) with the id of the NavController's graph and set inclusive to true.
旧答案
如果您不想遍历代码中的所有毛刺,则只需检查动作属性中
编辑:从Android Studio 3.2 Beta 5开始,"清除任务"在"启动选项"窗口中不再可见,但是您仍然可以通过添加以下标签在导航的XML代码中的操作标记中使用它:
1 | app:clearTask="true" |
我终于弄清楚了,这要归功于如何通过新的导航体系结构组件为某些片段禁用导航中的UP?
我必须将.setClearTask(true)指定为NavOption。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | 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()); } } }); |
这是我的工作方式。
1 2 3 4 5 6 | //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) |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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); } |
注意:这可能与实际问题无关。
如果需要在导航中维护片段的单个实例,则此方法将很有用。
1 2 3 4 5 6 7 8 9 | // 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 }) |
在这里,
在回答此问题时,我正在使用以下Gradle版本的Navigation UI。
1 2 3 4 5 | def nav_version ="2.2.0" implementation"androidx.navigation:navigation-ui:$nav_version" implementation"androidx.navigation:navigation-fragment:$nav_version" implementation"androidx.navigation:navigation-fragment-ktx:$nav_version" implementation"androidx.navigation:navigation-ui-ktx:$nav_version" |
您可以像这样覆盖基本活动的后退键:
1 2 3 4 5 6 7 8 9 10 11 12 | 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() } } |
我可以通过一个小例子对此进行解释。我有两个片段雇员列表和删除雇员。在删除员工中,我有两个单击事件,分别是取消和删除。如果我单击"取消",那么它仅返回到员工列表屏幕,如果我单击"删除",则我想清除所有以前的后退堆栈并转到员工列表屏幕。
要转到上一个屏幕:
1 2 3 4 5 6 7 8 | <action android:id="@+id/action_deleteEmployeeFragment_to_employeesListFragment2" app:destination="@id/employeesListFragment"/> btn_cancel.setOnClickListener { it.findNavController().popBackStack() } |
要清除所有先前的后退堆栈并转到新屏幕:
1 2 3 4 5 6 7 8 9 10 11 | <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导航示例
我努力了一段时间,以防止"后退"按钮返回到我的开始片段,在我的情况下,这是一个介绍性消息,应该只出现一次。
一种简单的解决方案是创建一个指向用户应停留的目的地的全局动作。您必须正确设置
您可以执行以下操作:
1 | getFragmentManager().popBackStack(); |
如果要检查计数,可以执行以下操作:
1 | getFragmentManager().getBackStackEntryCount() |