我在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);
答案 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
即可。
修改:从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,需要导入。
在回答此问题时,我正在使用以下
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())
}
答案 13 :(得分:-2)
您可以执行以下操作:
getFragmentManager().popBackStack();
如果要检查计数,可以执行以下操作:
getFragmentManager().getBackStackEntryCount()