导航组件不弹出片段

Navigation component doesn't pop fragment

当我们打开应用程序时,我会显示一个介绍片段。一段时间后,在介绍片段中,我将用户导航到提要片段。当用户按下后退按钮时,在提要片段上,我需要显示一个退出对话框。当用户点击退出时,我需要关闭应用程序。

这是我的导航图。

<navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/mobile_navigation"
app:startDestination="@+id/fragment_intro">

<fragment
    android:id="@+id/fragment_feed"
    android:name="FeedFragment"
    tools:layout="@layout/fragment_feed"/>

<fragment
    android:id="@+id/fragment_intro"
    android:name="IntroFragment"
    tools:layout="@layout/fragment_intro">

    <action
        android:id="@+id/action_introFragment_to_feedFragment"
        app:destination="@id/fragment_feed"
        app:enterAnim="@anim/slide_in_right"
        app:exitAnim="@anim/slide_out_left"
        app:popEnterAnim="@anim/slide_in_left"
        app:popExitAnim="@anim/slide_out_right"
        app:popUpTo="@id/mobile_navigation"
        app:popUpToInclusive="true" />

</fragment>
</navigation>

就是这样。我的起始目的地是 Intro 片段。我有一个操作,可以将我导航到提要片段。当我导航到提要片段时,我会弹出我的介绍片段。

关于代码,在介绍片段中,我在 3 秒后导航到提要片段。

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)

    Handler(Looper.getMainLooper()).postDelayed({
        val action = IntroFragmentDirections.actionIntroFragmentToFeedFragment()
        findNavController().navigate(action)
    }, 3000)
}

所以在提要片段中,当用户单击后退按钮时,我需要显示一个退出对话框。这意味着,我需要抓住后压,这是我用这种方式完成的。 在我的提要片段的 onCreateView() 中,我添加了这个

requireActivity().onBackPressedDispatcher.addCallback(
        viewLifecycleOwner, object : OnBackPressedCallback(true) {
            override fun handleOnBackPressed() {
                // Show exit dialog
            }
        }
    )

当用户点击后退按钮时,我简单地调用了这个函数

fun onExit() {
    findNavController().navigateUp()
}

但是当我单击退出按钮时,它 returns 返回到我弹出的介绍片段。那么为什么它没有弹出,我做错了什么?

---编辑---

一种解决方案是删除 dispatcherCallback 并调用 onBackPressed(),但我认为这不是一个好方法。

val onBackPressedCallback = object : OnBackPressedCallback(true) {
        override fun handleOnBackPressed() {
            // Show exit dialog
        }
    }
    
requireActivity().onBackPressedDispatcher.addCallback(
    viewLifecycleOwner, onBackPressedCallback 
)
    
fun onExit() {
    onBackPressedCallback.remove()
    activity?.onBackPressed()
}

谢谢。

一段时间后我找到了解决方案,也许这会对某人有所帮助。所以片段没有弹出的问题是,因为当我们的 backstack 中只有一个片段时,或者我们尝试弹出我们的起始目标片段时,navigateUp() 函数将 return false片段不会被弹出。那为什么会这样呢?因为 navigateUp 导航到导航主机中的上一个片段。但是如果没有片段,我们的导航控制器可以导航到哪里,它只是 returns false。所以我们需要一个函数来确定这是否是我们图中唯一的片段,我们不能向上导航也可以。因为每次都调用 activity?.onBackPressed() 不是一个好的解决方案。所以为了实现这一点,我们可以创建一个这样的扩展函数:

fun NavController.navigateUpOrFinish(activity: FragmentActivity): Boolean {
    return if (navigateUp()) {
        true
    } else {
        activity.finish()
        true
    }
}

就是这样。现在我们可以在对话框退出时调用这个函数 click

fun onExit() {
    findNavController().navigateUpOrFinish(requireActivity())
}

如果有一个片段,我们可以在其中导航,它会调用 navigateUp() 在其他情况下,它只会调用 backPressed 并且我们的应用程序将关闭。谢谢。