FragmentPagerAdapter和FragmentStatePagerAdapter的区别是什么?

关于FragmentPagerAdapter谷歌的指南说:

此版本的寻呼机最适合在有少量 通常需要分页更多的静态片段,例如一组 选项卡。用户访问的每个页面的片段将被保留 内存,尽管它的视图层次结构可能在不可见时被破坏。 这可能导致使用大量的内存,因为片段 实例可以保留任意数量的状态。对于较大的电视机 ,考虑FragmentStatePagerAdapter。

关于FragmentStatePagerAdapter:

这个版本的寻呼机在有大量数据时更有用 页面,工作起来更像一个列表视图。当页面不可见时 对用户来说,他们的整个碎片可能被销毁,只保留了 该片段的保存状态。这使得寻呼机可以保留很多信息 与。相比,与每个访问页面关联的内存更少 FragmentPagerAdapter以潜在的更多开销为代价 在页面之间切换。

所以我只有3个片段。但它们都是包含大量数据的独立模块。

Fragment1处理一些数据(用户输入的),并通过活动将其传递给Fragment2,这只是一个简单的ListFragment。Fragment3也是一个ListFragment。

所以我的问题是:我应该使用哪个适配器?FragmentPagerAdapter还是FragmentStatePagerAdapter?


当前回答

FragmentPagerAdapter:用户访问的每个页面的片段将存储在内存中,尽管视图将被销毁。因此,当页面再次可见时,视图将被重新创建,但片段实例不会被重新创建。这可能会导致占用大量内存。当我们需要在内存中存储整个片段时,应该使用FragmentPagerAdapter。FragmentPagerAdapter在事务上调用detach(Fragment)而不是remove(Fragment)。

FragmentStatePagerAdapter:当片段实例对用户不可见时销毁,除了保存的片段状态。这导致只使用少量的内存,对于处理较大的数据集非常有用。当我们必须使用动态片段时应该使用,比如带有小部件的片段,因为它们的数据可以存储在savedInstanceState中。而且即使有大量的片段也不会影响性能。

其他回答

FragmentPagerAdapter:用户访问的每个页面的片段将存储在内存中,尽管视图将被销毁。因此,当页面再次可见时,视图将被重新创建,但片段实例不会被重新创建。这可能会导致占用大量内存。当我们需要在内存中存储整个片段时,应该使用FragmentPagerAdapter。FragmentPagerAdapter在事务上调用detach(Fragment)而不是remove(Fragment)。

FragmentStatePagerAdapter:当片段实例对用户不可见时销毁,除了保存的片段状态。这导致只使用少量的内存,对于处理较大的数据集非常有用。当我们必须使用动态片段时应该使用,比如带有小部件的片段,因为它们的数据可以存储在savedInstanceState中。而且即使有大量的片段也不会影响性能。

下面是ViewPager中每个片段的日志生命周期,其中有4个片段,offscreenPageLimit = 1(默认值)

FragmentStatePagerAdapter

转到Fragment1(启动活动)

Fragment1: onCreateView
Fragment1: onStart
Fragment2: onCreateView
Fragment2: onStart

去Fragment2

Fragment3: onCreateView
Fragment3: onStart

进入Fragment3

Fragment1: onStop
Fragment1: onDestroyView
Fragment1: onDestroy
Fragment1: onDetach
Fragment4: onCreateView
Fragment4: onStart

去Fragment4

Fragment2: onStop
Fragment2: onDestroyView
Fragment2: onDestroy

FragmentPagerAdapter

转到Fragment1(启动活动)

Fragment1: onCreateView
Fragment1: onStart
Fragment2: onCreateView
Fragment2: onStart

去Fragment2

Fragment3: onCreateView
Fragment3: onStart

进入Fragment3

Fragment1: onStop
Fragment1: onDestroyView
Fragment4: onCreateView
Fragment4: onStart

去Fragment4

Fragment2: onStop
Fragment2: onDestroyView

结论:FragmentStatePagerAdapter在Fragment被offscreenPageLimit克服时调用onDestroy,而FragmentPagerAdapter没有。

注意:我认为我们应该使用FragmentStatePagerAdapter的ViewPager有很多页面,因为这将有利于性能。

offscreenPageLimit的示例:

如果我们转到Fragment3,它将破坏Fragment1(或者Fragment5),因为offscreenPageLimit = 1。如果我们设置offscreenPageLimit > 1,它不会破坏。 如果在这个例子中,我们设置offscreenPageLimit=4,使用FragmentStatePagerAdapter和FragmentPagerAdapter之间没有区别,因为当我们改变制表符时,Fragment从不调用onDestroyView和onDestroy

Github演示在这里

在文档或本页的答案中没有明确说明的事情(即使由@Naruto暗示)是,FragmentPagerAdapter将不会更新片段,如果片段中的数据发生变化,因为它将片段保存在内存中。

所以即使你有有限数量的片段显示,如果你想要能够刷新你的片段(例如你重新运行查询来更新片段中的listView),你需要使用FragmentStatePagerAdapter。

我在这里的全部观点是,片段的数量以及它们是否相似并不总是需要考虑的关键方面。你的片段是否是动态的也是关键。

不知道技术细节,但根据我的经验: 如果你尝试在一个片段中的viewPager中使用FragmentStatePagerAdapter,那么你的子片段的选项菜单可能会被搞砸(或者根本不显示),如果你导航到另一个页面并返回。但是它将与FragmentPagerAdapter一起工作。 据我所知,在用户单击一个选项卡之前,子片段的onCreateOptionsMenu没有被调用。这可能是有意的,但对我来说是一场噩梦。

在毫无希望的搜索中,我偶然发现了一些页面: https://issuetracker.google.com/issues/37092407 Viewpager片段的选项菜单显示彼此的按钮 嵌套片段在viewpager与不同的菜单

PS:任何使用FragmentStatePagerAdapter的优雅解决方案或建议都是受欢迎的

FragmentStatePagerAdapter =在ViewPager中容纳大量的片段。当片段对用户不可见时,这个适配器会销毁它,并且只保留片段的savedInstanceState以供进一步使用。在动态片段的情况下,这样可以使用较少的内存并提供更好的性能。