ViewPager和FragmentPagerAdapter中的片段的Android生命周期管理 [英] Android Lifecycle management of Fragments within ViewPager and FragmentPagerAdapter

查看:246
本文介绍了ViewPager和FragmentPagerAdapter中的片段的Android生命周期管理的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在努力寻找用ViewPagerFragmentActivity中对Fragments的正确管理是什么.在详细介绍之前,我先简要概述一下我所面临的问题:

I have been struggling to find out what the correct management of Fragments within a FragmentActivity with a ViewPager is. Before I go into details, a quick summary of the issue that I am facing is the following:

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

I have a FragmentActivity with a ViewPager. The ViewPager uses a custom, yet very simple FragmentPagerAdapter. Each Fragment within the ViewPager comprises of an ExpandableListView. I also have an action bar button called "Refresh". For now, let's assume that the ViewPager has only one Fragment. The activity is created, and the Fragment's ExpandableListView is populated (so far so good). When the Refresh button is clicked, the handling method within the FragmentActivity iterates over the list of Fragments that are assigned to the FragmentPagerAdapter and calls refresh() on each Fragment to populate its ListView. However, when the orientation of the device changes (e.g. from portrait to landscape), the Activity is recreated and so are the fragments. Clicking the Refresh button now will iterate over non-initialised Fragments.

我知道我很模糊,尤其是没有示例代码时,但是请耐心等待.从应用程序/活动的开始,我就跟踪了问题和方法调用,如下所示:

I know that I am being quite vague, especially without sample code, but please bear with me. I have traced the problem and method calls as follows from the start of the application/activity:

  1. FragmentActivity.onCreate()
  2. FragmentActivity.setContentView()
  3. FragmentActivity.createPagerFragments()<-创建一个ArrayArray of Fragments,并将它们分配给新的FragmentPagerAdapter,后者又分配给ViewPager.
  4. Fragment.onAttach()
  5. Fragment.onCreate()<-在这里没有什么特别的,只是调用了super方法.
  6. Fragment.onCreateView()<-在这里也没什么特别的,只是夸大了布局
  7. Fragment.onActivityCreated()<-这里也没有.
  8. <<一切都很好,方向在这里>>
  9. FragmentActivity.onCreate()
  10. Fragment.onAttach()
  11. Fragment.onCreate()
  12. FragmentActivity.setContentView()
  13. FragmentActivity.createPagerFragments()
  14. Fragment.onCreateView()
  15. Fragment.onActivityCreated()
  16. <<单击刷新按钮>>
  17. FragmentActivity.refresh()<-迭代#13上新创建的片段(Android则不行!).
  18. <<崩溃:Fragment中的mExpandableListView发生NullPointerException. >>
  1. FragmentActivity.onCreate()
  2. FragmentActivity.setContentView()
  3. FragmentActivity.createPagerFragments() <-- this creates an ArrayList of Fragments and assignes them to a new FragmentPagerAdapter which is in turn assigned to the ViewPager.
  4. Fragment.onAttach()
  5. Fragment.onCreate() <-- nothing special here, just calling the super method.
  6. Fragment.onCreateView() <-- nothing special here either, just inflating the layout
  7. Fragment.onActivityCreated() <-- nothing here either.
  8. << All good, orientation changes here >>
  9. FragmentActivity.onCreate()
  10. Fragment.onAttach()
  11. Fragment.onCreate()
  12. FragmentActivity.setContentView()
  13. FragmentActivity.createPagerFragments()
  14. Fragment.onCreateView()
  15. Fragment.onActivityCreated()
  16. << Refresh button clicked >>
  17. FragmentActivity.refresh() <-- iterates over the newly created Fragments from #13 (not these by Android!).
  18. << Crash: NullPointerException for mExpandableListView in Fragment. >>

因此,正如我所看到的,问题如下: 当Android在更改屏幕方向后重新创建FragmentActivity及其Views时(上面的调用#9-15),它将创建新的Fragment对象,其状态恢复为原始状态.但是,这些文件似乎完全由FragmentManager而不是FragmentPagerAdapter进行管理.相反,在活动的onCreate方法中重新创建FragmentPagerAdapterFragments时(请参阅调用#13),分配给适配器的Fragments永远不会具有其Fragment.onCreate()完全调用了方法.因此,当调用refresh()方法(请参阅#17)时,该方法将对尚未初始化的Fragments进行迭代.因此,当他们尝试填充ExpandableListView时,视图的实例变量为NULL.这是可以预期的,因为实例变量仅在Fragment.onCreateView()方法中分配,而从未在这些Fragments上调用.

So the problem, as I see it, is as follows: When Android re-creates the FragmentActivity and its Views after a change of screen orientation (calls #9-15 above), it creates new Fragment objects with their state restored to what the original ones were. However, these ones appear to be completely managed by the FragmentManager, and not by the FragmentPagerAdapter. In contrast, when the FragmentPagerAdapter is re-created along with the Fragments in the activity's onCreate method (see call #13) the Fragments that get assigned to the adapter never have their Fragment.onCreate() or Fragment.onCreateView() methods called at all. So when the refresh() method is called (see #17) the method iterates over these Fragments that have not been initialised. Therefore, when they try to populate the ExpandableListView, the view's instance variable is NULL. This is to be expected as the instance variable is only assigned in the Fragment.onCreateView() method that never gets called on these Fragments.

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

So my question is: how does one properly make re-use of the re-recreated (by Android) Fragments after the screen orientation has changed in order to avoid creating new ones that don't get initialised? I need to have a valid reference to them, in order to call their refresh() method that populates them on-demand. Ideally, they should also be assigned to the FragmentPagerAdapter as well.

我希望我已经清楚地描述了这个问题,而我没有提供示例代码的原因是因为(可以看到)问题不是源于代码本身,而是源于一个相当不正确的(seemigly)re-创建碎片而不是重复使用.但是如果需要,我可以给您示例代码,通过这种方式我会更清楚.

I hope I have been clear in describing the issue, and the reason that I have not provided sample code is because the problem (as can be seen) is not from the code itself but from a rather incorrect (seemigly) re-creation of Fragments rather than re-use. But if needed, I can give you sample code, I just through this way would be clearer.

谢谢!

推荐答案

要阅读很多东西,但是在阅读了介绍和问题并具有FragmentStatePagerAdapter的经验之后,我就可以告诉你:

It's lot to read, but after reading just introduction and the question and having experience with FragmentStatePagerAdapter, which is similar to FragmentPagerAdapter I can tell you that:

旋转后,适配器将自动附着旧碎片.因此看来,尽管正在重新创建活动创建适配器,但具有全局性且实例保留活动重新创建的FragmentManager会检测到新的FragmentStatePagerAdapter与相同的ViewPager组合在一起并请求相同的Fragments,并且只需从Fragment的BackStack中获取它们即可.

After rotation your adapter will AUTOMAGICALLY attach old fragments. So it seems that although activity creating adapter is being recreated, FragmentManager, which is global and it's instance preserve activity's recreation will detect that new FragmentStatePagerAdapter is combined with the same ViewPager and is asking for the same Fragments and will simply fetch them from Fragment's BackStack.

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

You as designer of Fragments can notice this behavior by continues invocation of Fragment.onAttach() and Fragment.onDetach(). When onAttach() occurs it's either creation of your Fragment or reusing it after rotation. You should be able to distinguish that Fragment was rotated with use of callback onRestoreRnstanceState().

您将在日志中同时看到许多onCreate()和其他状态日志,因为FragmentStatePagerAdapter总是获取/创建最少3个片段(除非您将它们设置为2或1),所以在屏幕旋转后,也会有3个片段从后堆栈重新连接.

You will see in your logs many onCreate() and other states logs simultaneously, because FragmentStatePagerAdapter always fetches/creates min 3 Fragments (except if you set that they are only 2 or 1), so also after screen rotation 3 fragments will be reattached from backstack.

我希望它能帮上忙.

这篇关于ViewPager和FragmentPagerAdapter中的片段的Android生命周期管理的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆