用导航组件实现循环逻辑的正确方法是啥
Posted
技术标签:
【中文标题】用导航组件实现循环逻辑的正确方法是啥【英文标题】:What is the correct way of implementing circular logic with the navigation component用导航组件实现循环逻辑的正确方法是什么 【发布时间】:2021-04-05 17:40:00 【问题描述】:我正在尝试使用 Navigation 组件实现循环逻辑,但我担心我做得不对,并且会不必要地调用生命周期方法。
我有 1 个包含 3 个片段的活动。片段之间的导航如下所示: A -> B -> C -> 回到 A 等等。
A 和 B 是常规片段,而 C 是 DialogFragment。 C 有两个按钮 - Cancel
和 Done
。如果按下Cancel
,则调用导航操作(使用findNavController().navigate(<action>)
),应用程序将显示A。如果按下Done
,则关闭C,应用程序将显示B,然后用户可以通过以下方式返回A压回去。这一切都按我的预期工作,但是......
我担心的是,返回 A 的每条路由都会导致在 A 中调用不同的生命周期方法。如果在用户接受 C 并按回 B 后导航返回 A,onCreateView()
、onViewCreated()
和 onResume()
由 A 调用。BUT,如果取消 C 后导航返回 A,A 会调用更多生命周期方法(onAttach()
.onCreate()
、onCreateView()
、onViewCreated
、onResume()
,onDestroy()
,onDetach()
)。为什么有区别?为什么在 A 中再次调用 onCreate()?它不应该只使用 A 的现有实例而不是创建一个新实例吗?
我不知道它为什么会这样,或者它是否是我应该关心的事情。我相信当用户在片段之间导航时,堆栈得到了适当的管理,因为 C 和 A 之间的导航操作使用 popUpTo
和 popUpToInclusive
属性(如文档中推荐的 here 那样)。我还尝试在 C 和 A 之间的操作中设置 launchSingleTop
属性,但我得到了相同的行为(在 A 中调用了额外的生命周期方法)。
这是 C 片段的 xml:
<dialog
android:id="@+id/C"
android:name="C"
... >
<action
android:id="@+id/C_to_A"
app:destination="@id/A"
app:popUpTo="@id/A"
app:popUpToInclusive="true" />
</dialog>
当用户按下 cancel
按钮时,我从 C 调用操作 C_to_A
。
非常欢迎任何帮助消除我的困惑。
【问题讨论】:
您在操作中使用app:destination
是否有原因(而不是忽略它并使用popUpToInclusive="false"
创建仅弹出操作)?使用app: destination
意味着您正在创建A
的新实例。
那我如何从 C 到 A?通过调用 findNavController().navigateUp() 两次?
嗯,很有趣。我只是尝试删除目标属性并将 popUpToInclusive 设置为 false,这似乎有效。 A 现在调用我期望的生命周期方法。我以为目的地是必需的?!谢谢@ianhanniballake
【参考方案1】:
一个动作有两个步骤:
-
弹出通过
popUpTo
/popUpToInclusive
设置的任何目的地
通过app:destination
导航(即创建新实例)目标集
操作可以是弹出、导航或两者的任意组合 - 当您右键单击目的地并选择“新建操作”时,导航编辑器中的 UI 将为您提供这些选项中的每一个。
因此,如果您想要一个仅弹回到您知道在后台堆栈上的目标的操作,那么您可以删除您的 app:destination
属性并且只弹出:
<action
android:id="@+id/C_to_A"
app:popUpTo="@id/A"
app:popUpToInclusive="false" />
请注意,通过使用app:popUpToInclusive="false"
,您可以确保A
在执行操作后位于堆栈顶部。
【讨论】:
以上是关于用导航组件实现循环逻辑的正确方法是啥的主要内容,如果未能解决你的问题,请参考以下文章
用 JavaScript 实现手势库 — 手势逻辑前端组件化