导航popUpTo和PopUpToInclusive不会清除后退堆栈

时间:2019-05-01 07:01:25

标签: android kotlin navigation android-jetpack fragment-backstack

我是Android Jetpack导航架构的新手。我正在一个新的应用程序上尝试。有一个活动和一些片段,其中两个是登录屏幕和电子邮件登录屏幕。我在导航XML中定义了这些片段。该应用程序的流程如下:

Login screenEmail Login screen

我想要的是,导航到电子邮件登录屏幕后,当我按返回时,该应用程序退出。表示已删除登录屏幕的后堆栈。我知道登录屏幕不应该这样工作,但是我仍然只是想办法解决问题。

我遵循了Google Get started with the Navigation component的文档。它说,使用app:popUpToapppopUpToInclusive="true"应该清除后退堆栈,但是当我在电子邮件登录屏幕上按回去时,它仍然返回登录而不是退出。

所以,这就是我尝试过的。

nav_main.xml

<fragment android:id="@+id/loginFragment"
          android:name="com.example.myapp.ui.main.LoginFragment"
          android:label="@string/login"
          tools:layout="@layout/fragment_login" >

    <action
        android:id="@+id/action_login_to_emailLoginFragment"
        app:destination="@id/emailLoginFragment"
        app:popEnterAnim="@anim/slide_in_right"
        app:popExitAnim="@anim/slide_out_right"
        app:popUpTo="@+id/emailLoginFragment"
        app:popUpToInclusive="true"/>

</fragment>

<fragment android:id="@+id/emailLoginFragment"
          android:name="com.example.myapp.ui.main.EmailLoginFragment"
          android:label="EmailLoginFragment"
          tools:layout="@layout/fragment_login_email" />

LoginFragment.kt

override fun onCreateView(
    inflater: LayoutInflater, container: ViewGroup?,
    savedInstanceState: Bundle?
): View {
    binding.emailLoginButton.setOnClickListener {
        findNavController().navigate(R.id.action_login_to_emailLoginFragment)
    }

    return binding.root
}

我为按钮提供了click事件。在其中,我使用了导航控制器,通过为其提供操作的ID导航到电子邮件登录屏幕。在<action>中,有app:popUpToapp:popUpToInclusive="true"

一遍又一遍地阅读文档,并阅读了许多StackOverflow问题之后,我发现这些属性应该可以将我的登录屏幕从后栈中删除。但是他们没有。该按钮确实导航到电子邮件登录屏幕,但是当我按返回时,它仍然返回登录屏幕,而不是退出应用程序。我想念什么?

6 个答案:

答案 0 :(得分:4)

假设您的应用有三个目的地——A、B 和 C——以及从 A 到 B、B 到 C、C 回到 A 的操作。相应的导航图如图所示

A circular navigation graph with three destinations: A, B, and C.

对于每个导航操作,都会将一个目的地添加到返回堆栈中。如果您要在此流程中重复导航,那么您的返回堆栈将包含每个目的地的多个集合(A、B、C、A、B、C、A 等)。为避免这种重复,您可以在将您从目的地 C 带到目的地 A 的操作中指定 app:popUpTo 和 app:popUpToInclusive,如下例所示:

<fragment
android:id="@+id/c"
android:name="com.example.myapplication.C"
android:label="fragment_c"
tools:layout="@layout/fragment_c">

<action
    android:id="@+id/action_c_to_a"
    app:destination="@id/a"
    app:popUpTo="@+id/a"
    app:popUpToInclusive="true"/>

到达目的地 C 后,返回堆栈包含每个目的地(A、B、C)的一个实例。当导航回目的地 A 时,我们也会 popUpTo A,这意味着我们在导航时从堆栈中移除了 B 和 C。使用 app:popUpToInclusive="true",我们还从堆栈中弹出第一个 A,有效地清除它。请注意,如果您不使用 app:popUpToInclusive,则返回堆栈将包含目标 A 的两个实例

答案 1 :(得分:1)

如果您像enter link description here一样在xml中进行编辑

如果要在这样的代码中弹出

NavOptions navOptions = new NavOptions.Builder().setPopUpTo(R.id.loginRegister, true).build();
            Navigation.findNavController(mBinding.titleLogin).navigate(R.id.login_to_main, null, navOptions);

答案 2 :(得分:1)

popUpInclusive = true 它定义了当你按下返回时你想去的地方。如果您设置 popUpTo,导航也会跳过该位置(在 {{1}} 中)。

答案 3 :(得分:0)

<action
        android:id="@+id/action_login_to_emailLoginFragment"
        app:destination="@id/emailLoginFragment"
        app:popEnterAnim="@anim/slide_in_right"
        app:popExitAnim="@anim/slide_out_right"
        app:popUpTo="@+id/loginFragment"
        app:popUpToInclusive="true"/>

您的popUpTo将返回到电子邮件登录,而不是因为包含在内而将其弹出。 如果将popUpTo更改为登录片段,由于包含标记,它将被导航回并弹出,这将导致所需的行为。

答案 4 :(得分:0)

这2行使技巧起作用:

如果您要从A转到B并希望完成A:

您需要通过以下操作呼叫B:

    <fragment
        android:id="@+id/fragmentA"            
        tools:layout="@layout/fragment_a">

        <action
            android:id="@+id/action_call_B"
            app:destination="@+id/fragmentB"
            app:popUpTo="@id/fragmentA"
            app:popUpToInclusive="true" />

    </fragment>

    <fragment
        android:id="@+id/fragmentB"
        tools:layout="@layout/fragment_b">


    </fragment>

如果将日志记录到片段中,您可以看到通过此操作调用fragmentB后fragmentA被破坏了。

答案 5 :(得分:0)

示例:A -> B -> A

FragmentB.kt

尝试弹出控制器的返回栈

private fun popBackStackToA() {
    if (!findNavController().popBackStack()) {
//            Call finish on your Activity
        requireActivity().finish()
    }
}

Back Stack