You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Android中导航至新Fragment后如何清除导航栈

解决Navigation Component跳转后无法清除登录页导航栈的问题

我明白你遇到的问题——登录成功跳转到主页后,用户按返回键居然还能回到登录页,这确实不符合预期。咱们来看看问题出在哪,以及怎么解决。

你的代码问题所在

你之前尝试用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

这种方式更简洁,把跳转规则写在导航图里,代码里直接调用即可:

  1. 打开你的导航图文件,找到loginFragmenthomeFragment的action,添加popUpTopopUpToInclusive属性:
<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>
  1. 然后在代码里直接调用这个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

火山引擎 最新活动