ViewPager 和 FragmentPagerAdapter 中 Fragment 的 Android 生命周期管理
Posted
技术标签:
【中文标题】ViewPager 和 FragmentPagerAdapter 中 Fragment 的 Android 生命周期管理【英文标题】:Android Lifecycle management of Fragments within ViewPager and FragmentPagerAdapter 【发布时间】:2013-12-19 17:52:36 【问题描述】:我一直在努力找出FragmentActivity
和ViewPager
中的片段的正确管理是什么。在我详细介绍之前,我所面临的问题的简要总结如下:
我有一个FragmentActivity
和一个ViewPager
。 ViewPager
使用自定义但非常简单的FragmentPagerAdapter
。 ViewPager
中的每个Fragment
都包含一个ExpandableListView
。我还有一个名为“刷新”的操作栏按钮。现在,我们假设ViewPager
只有一个Fragment
。活动已创建,Fragment
的 ExpandableListView
已填充(到目前为止一切正常)。单击 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的使用