使用导航控制器创建两次的片段

Posted

技术标签:

【中文标题】使用导航控制器创建两次的片段【英文标题】:Fragment created twice with navigation controller 【发布时间】:2021-11-03 12:06:00 【问题描述】:

在应用程序中,我们启动了一个新的 Activity,其中包含一个片段,我们称之为 A。最近添加了导航组件,并且转换跟随导航图。

所以最初它是由

        navController = findNavController(R.id.nav_host_fragment)
        val graphInflater = navController.navInflater
        val navGraph = graphInflater.inflate(R.navigation.something_graph)

        val startDestination: Int = something

        navGraph.startDestination = startDestination
        navController.setGraph(navGraph, intent.extras)

之后,用户做了一些动作,调用了一个新的片段,比如说片段 B,然后我们需要回到片段 A。

目前,这是由

完成的
findNavController().navigate(SomethingGraphDirections.actionGlobalNavSomethingFragment(action, destination))

不幸的是,这会导致片段 A(不是活动)作为新实例被调用两次,然后按照与 this post 类似的描述调用 delete。

我可以通过在日志上打印this 语句来验证它。

Activity com.sen.osmo.ui.SomethingActivity@aad8485 onCreate
Fragment SomethingFragment1c32bd3 (325a1bc9-d922-49ff-8d0a-65e35427d109) id=0x7f0901c8 onCreateView

action
Fragment SomethingFragmentfd9bbac (eedc20a5-49b1-481c-8045-4cd60c427c78) id=0x7f0901c8 onCreateView
Fragment SomethingFragment1c32bd3 (325a1bc9-d922-49ff-8d0a-65e35427d109) id=0x7f0901c8 onDestroy

normal end of cycle and actions 

Fragment SomethingFragmentfd9bbac (eedc20a5-49b1-481c-8045-4cd60c427c78) id=0x7f0901c8 onDestroy
Activity com.sen.osmo.ui.SomethingActivity@aad8485 onDestroy 

尝试使用旧代码而不是 findNavController().navigate 在一定程度上解决了这个问题。这是

        if (fragmentManager!!.backStackEntryCount > 0) 
            fragmentManager!!.popBackStack()
         else 
           ...
        
        fragmentManager!!.beginTransaction().remove(this).commitAllowingStateLoss()

结果是在同一个实例上调用了两次 create,并且没有调用 onDestroy。

Activity onCreate com.sen.osmo.ui.SomethingActivity@96035a6
Fragment onCreateView, savedInstance: true SomethingFragment44b835a (d5190920-63a8-4356-bf02-41936dd710a5) id=0x7f0901c8

action
Fragment onCreateView, savedInstance: true SomethingFragment44b835a (d5190920-63a8-4356-bf02-41936dd710a5) id=0x7f0901c8

Fragment onDestroy SomethingFragment44b835a (d5190920-63a8-4356-bf02-41936dd710a5) id=0x7f0901c8
Activity onDestroy com.sen.osmo.ui.SomethingActivity@96035a6

这种方法正确吗?

但是,现在这是一个不推荐使用的方法,我发现我们应该使用

   requireActivity().supportFragmentManager

但这给出了一个例外

  java.lang.IllegalStateException: Cannot remove Fragment attached to a different FragmentManager.

那么最终我们应该使用什么解决方案呢?有没有办法使用导航控制器弹出片段B,以便在不使用导航的情况下返回片段A?

【问题讨论】:

实际上没有,应该吗?该应用程序不使用图表导航,仅使用关于一个特定活动和这两个片段的操作 @memres 你能从你的评论中删除图表的名称 **_graph 吗?在问题中包含名称是我的错误,我已对其进行了编辑。 将其添加到清单中,没有任何改变 我删除了我的第一条评论。无法编辑。不,您不应该在清单和代码中都有 nav_graph。我在片段的两个实例中遇到了类似的问题。原因是,我有两次导航图。一次在 androidManifest 中,一次在像你这样的代码中。从 AndroidManifest 中删除 NavGraph 解决了我的问题。但我认为你的情况还有另一个问题。 感谢cmets,不幸的是,这似乎是另一个问题 【参考方案1】:

我终于找到了答案,而不是导航回你想要的片段,你需要从后台堆栈中弹出它们。这不会创建新实例,并且生命周期是正确的。

            findNavController().popBackStack(R.id.nav_something_fragment, false)

最后也看到this answer也这么说

【讨论】:

以上是关于使用导航控制器创建两次的片段的主要内容,如果未能解决你的问题,请参考以下文章

如果使用导航控制器,如何删除某些片段中的底部导航视图和工具栏?

使用导航控制器按下后退按钮后如何防止前一个片段显示?

在导航控制器中杀死片段

使用导航控制器按下后退按钮后,如何防止先前的片段出现?

如何使用新的导航架构组件从扩展 BroadcastReceiver 的类导航到片段

使用导航架构组件添加(而不是替换)片段