繁体   English   中英

导航架构组件 - OnBackPressed() - Android

[英]Navigation Architecture Component - OnBackPressed() - Android

我使用 Android 导航架构在片段中取得进展。

当我在最后一个屏幕上按下键或在屏幕上放置一个按钮并将按钮 function 设置为

val navıgattor = activity.findNavController(R.id.nav_host_fragment)
navigator.popBackStack()

并点击,我回到了上一个fragment,但是又调用了上一个fragment中的onCreateView()方法。 我期待它保持 state 的正常行为。

我在哪里做错了?

我分两部分回答——

解决方案:

每次返回上一个片段时不要放大视图。 将 View 保存在局部变量中并仅对其进行一次膨胀。 Ian Lake推荐这里

private var savedViewInstance: View? = null

override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
): View? {
    return if (savedViewInstance != null) {
        savedViewInstance
    } else {
        savedViewInstance =
                inflater.inflate(R.layout.fragment_professional_details, container, false)
        savedViewInstance
    }
}

解释

您得到的行为是默认行为,片段将在您每次调用navigator.popBackStack()或使用设备上的后退按钮时重新创建它们的视图。

让我们了解导航架构下片段的生命周期。

场景:我们采用两个片段,HomeFragment 和 DashboardFragment。 两个片段都属于同一个 NavGraph,起始目的地是 Home Fragment。

应用程序启动时的片段生命周期-

HomeFragment:onAttach:

HomeFragment: onCreate:

HomeFragment:onCreateView:

HomeFragment:onViewCreated:

HomeFragment:onActivityCreated:

HomeFragment:onStart:

HomeFragment: onResume:

在导航上:主页片段 ---> 仪表板片段

仪表板片段:onAttach:

仪表板片段:onCreate:

仪表板片段:onCreateView:

仪表板片段:onViewCreated:

DashboardFragment:onActivityCreated:

仪表板片段:onStart:

仪表板片段: onResume:

HomeFragment:onPause:

HomeFragment:onStop:

HomeFragment: onDestroyView:

在导航上:仪表板片段 ---> 主页片段

HomeFragment:onAttach:

HomeFragment: onCreate:

HomeFragment:onCreateView:

HomeFragment:onViewCreated:

HomeFragment:onActivityCreated:

HomeFragment:onStart:

HomeFragment: onResume:

仪表板片段:onPause:

DashboardFragment: onStop:

HomeFragment: onDestroy:

仪表板片段:onDestroyView:

仪表板片段:onDestroy:

如果我们在初始 HomeFragment: onCreateView() 上保存视图并在每次调用 HomeFragment: onCreateView() 时膨胀相同的视图,我们可以恢复旧视图。

如果您注意到HomeFragment: onDestroy()将被调用,但在HomeFragment: onViewCreated()调用之后。 HomeFragment: onDestroy()只是破坏 HomeFragment 的旧实例。

我仍然相信这种做事方式不是最佳实践,但直到谷歌会提出类似onFragemntRestore()的东西。

另一方面,假设每次删除或替换片段时都会重新创建片段,并且您应该使用onSaveInstanceState()恢复那里的状态。

ViewModel 来了保存片段 state 并恢复它们的喧嚣。 要实际更新视图,您必须需要 ViewModel 并观察视图中的更改。

在此处输入图像描述 简而言之,如果您有something可以为您的视图处理数据,无论您身在何处,如果您返回相同的 position 而不进行任何更改,则该something包含有关您之前查看的信息。 something ViewModel

还有很多其他值得一读的关于同一个主题的文章,比如这个这个这个

快乐编码!

您没有做错任何事情,这种行为对于片段来说是正常的。 当您导航到另一个片段时,片段管理器只保存事务,而不保存当前片段的 state。

要保存片段的实例 state,您可以覆盖onSaveInstanceState() function 并将数据放入状态包中。 要检索保存的数据,您可以覆盖onActivityCreated()并检查数据是否包含在 savedInstanceState 包中。

您可以在此处查看片段生命周期:

在此处输入图像描述

从片段文档:

/**
 * Called when the view previously created by {@link #onCreateView} has
 * been detached from the fragment.  The next time the fragment needs
 * to be displayed, a new view will be created.  This is called
 * after {@link #onStop()} and before {@link #onDestroy()}.  It is called
 * <em>regardless</em> of whether {@link #onCreateView} returned a
 * non-null view.  Internally it is called after the view's state has
 * been saved but before it has been removed from its parent.
 */
public void onDestroyView()

因此,无论何时调用 onDestroyView (无论出于何种原因),当片段回到顶部时,您都会看到 onCreateView 被调用。 为了重新获得视图的 state,需要考虑一些工具(您可以决定哪一种或哪种组合适合您):

1-覆盖onSaveInstanceState,将当前state作为bundle传递,并在android系统以bundle作为参数调用onCreateView时重用它。

2- 使用包含视图 state 信息的ViewModel ,该信息与 Fragment、其视图或其父 Activity 绑定,并与此类信息一起被销毁。

3- 在片段中保留由 onCreateView 返回的视图 object 的副本,并在再次调用 onCreateView 时重新使用它,如果不是 null (请谨慎使用,因为某些视图可能会在重绘时遇到麻烦,例如OSM MapView ):

private var viewCopy : View? = null
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
    if(viewCopy!=null)
        return viewCopy
    ...
    viewCopy = inflatedView
    return viewCopy
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM