Android中导航至新Fragment后如何清除导航栈
我明白你遇到的问题——登录成功跳转到主页后,用户按返回键居然还能回到登录页,这确实不符合预期。咱们来看看问题出在哪,以及怎么解决。
你的代码问题所在
你之前尝试用NavOptions时,写了setPopUpTo(R.id.homeFragment, false),这其实完全没起到清除登录页的作用:
setPopUpTo()的第一个参数是要弹出到的目的地ID,你填的homeFragment此时还没被添加到导航栈里,这个设置自然无效;- 第二个参数
false表示不包含指定的目的地,但这里连目标都不对,所以根本没法清除登录页。
正确的解决方法
有两种常用的方式可以实现登录后清除登录页,让返回键直接退出App:
方法一:在代码中配置NavOptions
我们需要指定弹出到loginFragment,并且包含它一起从栈中移除(设置inclusive=true):
mAuth.signInWithCredential(credential) .addOnCompleteListener(getActivity(), new OnCompleteListener<AuthResult>() { @Override public void onComplete(@NonNull Task<AuthResult> task) { if (task.isSuccessful()) { NavOptions navOptions = new NavOptions.Builder() // 弹出到loginFragment,并且将它也从栈中清除 .setPopUpTo(R.id.loginFragment, true) .build(); NavHostFragment.findNavController(LoginFragment.this) .navigate(R.id.homeFragment, null, navOptions); } else { Log.w(TAG, "signInWithCredential:failure", task.getException()); } } });
方法二:在导航图(nav_graph.xml)中配置Action
这种方式更简洁,把跳转规则写在导航图里,代码里直接调用即可:
- 打开你的导航图文件,找到
loginFragment到homeFragment的action,添加popUpTo和popUpToInclusive属性:
<fragment android:id="@+id/loginFragment" android:name="com.yourpackage.LoginFragment" android:label="LoginFragment"> <action android:id="@+id/action_login_to_home" app:destination="@id/homeFragment" <!-- 弹出到loginFragment并包含它 --> app:popUpTo="@id/loginFragment" app:popUpToInclusive="true"/> </fragment>
- 然后在代码里直接调用这个action:
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.action_login_to_home); } else { Log.w(TAG, "signInWithCredential:failure", task.getException()); } } });
额外小技巧
如果loginFragment是你的导航图起始页(startDestination),可以用更通用的写法,不用硬编码loginFragment的ID:
NavController navController = NavHostFragment.findNavController(LoginFragment.this); NavOptions navOptions = new NavOptions.Builder() .setPopUpTo(navController.getGraph().getStartDestinationId(), true) .build(); navController.navigate(R.id.homeFragment, null, navOptions);
这样就算以后修改起始页,这段代码也不用改动。
内容的提问来源于stack exchange,提问作者Youssef El Behi




