ViewPager 和 FragmentPagerAdapter 中 Fragment 的 Android 生命周期管理

Posted

技术标签:

【中文标题】ViewPager 和 FragmentPagerAdapter 中 Fragment 的 Android 生命周期管理【英文标题】:Android Lifecycle management of Fragments within ViewPager and FragmentPagerAdapter 【发布时间】:2013-12-19 17:52:36 【问题描述】:

我一直在努力找出FragmentActivityViewPager 中的片段的正确管理是什么。在我详细介绍之前,我所面临的问题的简要总结如下:

我有一个FragmentActivity 和一个ViewPagerViewPager 使用自定义但非常简单的FragmentPagerAdapterViewPager 中的每个Fragment 都包含一个ExpandableListView。我还有一个名为“刷新”的操作栏按钮。现在,我们假设ViewPager 只有一个Fragment。活动已创建,FragmentExpandableListView 已填充(到目前为止一切正常)。单击 Refresh 按钮时,FragmentActivity 中的处理方法将遍历分配给 FragmentPagerAdapter 的 Fragments 列表,并在每个 Fragment 上调用 refresh() 以填充其 ListView。但是,当设备的方向发生变化时(例如从纵向变为横向),Activity 会重新创建,片段也会重新创建。现在单击刷新按钮将遍历未初始化的Fragments

我知道我说的很模糊,尤其是没有示例代码,但请多多包涵。我从应用程序/活动的开始跟踪问题和方法调用如下:

    FragmentActivity.onCreate() FragmentActivity.setContentView() FragmentActivity.createPagerFragments() Fragment.onAttach() Fragment.onCreate() Fragment.onCreateView() Fragment.onActivityCreated() > FragmentActivity.onCreate() Fragment.onAttach() Fragment.onCreate() FragmentActivity.setContentView() FragmentActivity.createPagerFragments() Fragment.onCreateView() Fragment.onActivityCreated() > FragmentActivity.refresh() >

所以,在我看来,问题如下: 当 android 在屏幕方向改变后重新创建 FragmentActivity 及其 Views 时(上面调用 #9-15),它会创建新的 Fragment 对象,并将其状态恢复到原始状态。然而,这些似乎完全由FragmentManager 管理,而不是由FragmentPagerAdapter。相反,当FragmentPagerAdapter 与活动的onCreate 方法中的Fragments 一起重新创建时(参见调用#13),分配给适配器的Fragments 永远不会有它们的Fragment.onCreate() 或@987654364 @ 方法完全调用。因此,当调用 refresh() 方法时(参见 #17),该方法将遍历这些尚未初始化的 Fragments。因此,当他们尝试填充ExpandableListView 时,视图的实例变量是NULL。这是意料之中的,因为实例变量仅在 Fragment.onCreateView() 方法中分配,而不会在这些 Fragments 上调用。

所以我的问题是:如何在屏幕方向改变后正确地重新使用重新创建的(由 Android)Fragments 以避免创建新的不没有初始化?我需要对它们有一个有效的引用,以便调用它们的 refresh() 方法来按需填充它们。理想情况下,它们也应该分配给FragmentPagerAdapter

我希望我已经清楚地描述了这个问题,而我没有提供示例代码的原因是因为问题(可以看出)不是来自代码本身,而是来自一个相当不正确(看似)的重新 -创建片段而不是重复使用。但是如果需要,我可以给你示例代码,我只是通过这种方式会更清楚。

谢谢!

【问题讨论】:

嗨!我有同样的问题,你是怎么解决的,因为下面的答案不是很有用) 【参考方案1】:

阅读内容很多,但在阅读了介绍和问题以及使用类似于 FragmentPagerAdapter 的 FragmentStatePagerAdapter 的经验之后,我可以告诉你:

旋转后,您的适配器将自动附加旧片段。因此,似乎虽然正在重新创建活动创建适配器,但 FragmentManager 是全局的,并且它的实例保留活动的重新创建将检测到新的 FragmentStatePagerAdapter 与相同的 ViewPager 组合并要求相同的 Fragment,并且只会从 Fragment 的 BackStack 中获取它们。

作为 Fragment 的设计者,您可以通过继续调用 Fragment.onAttach() 和 Fragment.onDetach() 来注意到这种行为。当 onAttach() 发生时,它要么是创建 Fragment,要么是在旋转后重用它。您应该能够区分 Fragment 是使用回调 onRestoreRnstanceState() 旋转的。

您将在日志中同时看到许多 onCreate() 和其他状态日志,因为 FragmentStatePagerAdapter 总是获取/创建至少 3 个片段(除非您将它们设置为仅 2 或 1 个),因此屏幕旋转后 3 个片段也会从后台重新附加。

希望对你有所帮助。

【讨论】:

【参考方案2】:

我相信这个关于从 ViewPager 检索当前片段的question 会对您有所帮助。正如已经指出的,Fragment 由 Fragment(State)PagerAdapter 管理,而不是 Activity 或 Fragment 的生命周期。

第一次创建活动时,片段由getItem 方法返回。即使重新创建了 Activity,每个 Fragment 仅调用此方法一次。 随后,片段由instantiateItem 方法返回。很可能,这是您需要获取片段并调用其刷新方法的地方。

【讨论】:

【参考方案3】:

如何将其添加到清单中的活动标签:

android:configChanges="orientation"

或者对于 API 13 或更高版本

android:configChanges="orientation|screenSize" 

所以当它改变方向时它不会重新创建你的片段..

【讨论】:

最好避免这种情况。除其他外,它不允许您对横向和纵向方向(来自 XML)进行单独的布局。此外,它只是将问题隐藏在地毯下。当 Activity 因内存不足而被销毁然后被重新创建时,也会发生类似的情况。

以上是关于ViewPager 和 FragmentPagerAdapter 中 Fragment 的 Android 生命周期管理的主要内容,如果未能解决你的问题,请参考以下文章

Android ------ ViewPager1和ViewPager2的使用

Android ------ ViewPager1和ViewPager2的使用

Android ------ ViewPager1和ViewPager2的使用

Android ------ ViewPager1和ViewPager2的使用

viewpager和viewpager冲突

如何使用导航抽屉和viewpager/viewpager2在java中制作android应用程序