FragmentPagerAdapter和FragmentStatePagerAdapter有什么区别?


374

FragmentPagerAdapter和之间有什么区别FragmentStatePagerAdapter

关于FragmentPagerAdapterGoogle的指南说:

此版本的分页器最适合用于少数几个通常要分页的静态片段,例如一组选项卡。用户访问的每个页面的片段都将保留在内存中,尽管其视图层次结构在不可见时可能会被破坏。由于片段实例可以保持任意数量的状态,因此这可能导致使用大量内存。对于较大的页面集,请考虑FragmentStatePagerAdapter

关于FragmentStatePagerAdapter

当存在大量页面(更像列表视图)时,此版本的分页器会更加有用。当页面对用户不可见时,它们的整个片段可能会被破坏,仅保留该片段的保存状态。与页面FragmentPagerAdapter之间切换时潜在的更多开销相比,这使寻呼机可以保留与每个被访问页面关联的更少的内存 。

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

Fragment1处理一些数据(用户输入)并通过活动将其传递到Fragment2,这很简单ListFragmentFragment3也是ListFragment

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


2
我认为只有3个Fragments才有资格使用FragmentPagerAdapter。这些片段的选项卡可能都将同时可见。
IgorGanapolsky

2
这篇文章救了我的5-6个小时,因为我用错类型的适配器
Nantaphop

1
回答这个问题抛出一个问题stackoverflow.com/questions/9156406/...
的Piyush Kukadiya

FragmentPagerAdapterFragmentStatePagerAdapter但是什么FragmentStateAdapter
the_prole

Answers:


291

就像文档所说的那样,以这种方式思考。如果要像书本阅读器这样的应用程序,则不希望立即将所有片段都加载到内存中。您希望Fragments在用户阅读时加载和销毁。在这种情况下,您将使用FragmentStatePagerAdapter。如果您仅显示3个“标签”,其中不包含很多繁重的数据(例如Bitmaps),则FragmentPagerAdapter可能非常适合您。另外,请记住,ViewPager默认情况下会将3个片段加载到内存中。Adapter您提到的第一个可能会破坏View层次结构并在需要时重新加载它,第二个Adapter仅保存的状态Fragment并完全破坏它,如果用户随后返回该页面,则将检索该状态。


我在Fragment1和ListView中有多个Button和TextViews,它们在Fragment2和Fragment3中动态生成项目。您是否认为使用FragmentStatePagerAdapter并将所有数据存储在Activity中,然后通过Bundle将其传递给Fragments是个好主意吗?
AlexMomotov

2
片段布局中的@AlexMomotov视图与FragmentStatePagerAdapter的选择无关。这里的问题是将分页通过的片段数量。
IgorGanapolsky

1
因此,基本上没有什么FragmentPagerAdapter可以使用它的。
Tomasz Mularczyk

3
@Tomasz的优点FragmentPagerAdapter是片段之间的切换可能要快得多,因为Fragment不需要每次都重建实际对象。另一方面,这最终将使用更多的内存来将片段对象保存在内存中。
理查德·勒·马苏里尔

我有3个标签/页面(每个都显示一个WebView),因此使用了FragmentPagerAdapter。但是,当我从第一页滑到最后一页时,最后一页仍会重绘。为了解决这个问题,我使用了viewPager.setOffscreenPageLimit(2)
ban-geoengineering

131
  • FragmentPagerAdapter将整个片段存储在内存中,如果在中使用了大量片段,可能会增加内存开销 ViewPager

  • 相反,其同级FragmentStatePagerAdapter仅存储片段的savedInstanceState,并在失去焦点时销毁所有片段。

  • 因此,FragmentStatePagerAdapter当我们必须使用动态片段(如带有窗口小部件的片段)时,应使用它们,因为它们的数据可以存储在savedInstanceState。即使存在大量片段,它也不会影响性能。

  • 相反,FragmentPagerAdapter当我们需要将整个片段存储在内存中时,应使用其同级。

  • 当我说整个片段都保存在内存中时,这意味着它的实例不会被破坏并会产生内存开销。因此,建议FragmentPagerAdapter仅在的片段数量较少时使用ViewPager

  • 如果片段是静态的,那会更好,因为它们不会有大量对象将要存储的实例。

更详细地说,

FragmentStatePagerAdapter:

  • FragmentStatePagerAdapter,你不需要的片段是destroyed.A事务被提交到完全从您的活动的删除片段FragmentManager

  • 进入状态FragmentStatePagerAdapter的事实是,它会从碎片被销毁时保存下来BundlesavedInstanceState当用户向后导航时,新的碎片将使用碎片的状态进行还原。

FragmentPagerAdapter:

  • 通过比较FragmentPagerAdapter不会做任何事情,不再需要片段时。FragmentPagerAdapter呼叫 detach(Fragment)交易而不是remove(Fragment)

  • 该销毁是片段的视图,但是使片段的实例FragmentManager保留在FragmentPagerAdapter.. 中,因此永不销毁在中创建的片段 。


2
为什么有2个答案?
Jared Burrows

将整个碎片保留在内存中有什么好处?
Tomasz Mularczyk

4
@Tomek:如果已经实例化了下一个片段(即FragmentPagerAdapter),则在向其滑动时将可以渲染该片段,因此滑动动画将更加平滑。使用FragmentStatePagerAdapter,在您滑动到下一个片段实例之前,可能不存在下一个片段实例;如果它是一个很大的片段,且创建成本很高,则动画中可能会出现断断续续的情况。这是性能与内存消耗的问题。
黄檀

1
@Jared Burrows bcoz一个只是AnswerText,它适用于较小且静态的答案,另一个是AnswerStateText,其适用于较大且动态的答案
Simple Fellow,

48

这是每个片段的日志生命周期,ViewPager其中有4个片段,offscreenPageLimit = 1 (default value)

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调用。 onDestroyoffscreenPageLimitFragmentPagerAdapter

注意:我认为我们应该在页面很多的情况下使用FragmentStatePagerAdapterViewPager因为它会提高性能。

示例offscreenPageLimit

如果我们去Fragment3,它 detroy片段1(或Fragment5如果有),因为offscreenPageLimit = 1。如果我们设置offscreenPageLimit > 1不会破坏。
如果在此示例中,我们设置offscreenPageLimit=4,则使用FragmentStatePagerAdapterFragmentPagerAdapter因为Fragment从不调用onDestroyViewonDestroy更改标签之间没有区别

Github演示在这里


这么棒的结论!
拉胡尔·拉斯托吉

很好的解释
gourav singhal

1
很好的解释。您说过,在有很多页面时使用FragmentStatePagerAdapter可以提高性能。您是说这对节省内存有好处吗?据我了解,目标是在可能有许多Fragment实例的情况下保留内存-因此性能是隐式的好处;明确的目标是保留记忆
Hatzil

38

文档或本页答案中没有明确说明的内容(即使@Naruto暗示)是,FragmentPagerAdapter如果Fragment中的数据发生更改,则不会更新Fragment,因为它将Fragment保留在内存中。

因此,即使要显示的片段数量有限,如果您希望能够刷新片段(例如,您重新运行查询以更新片段中的listView),也需要使用FragmentStatePagerAdapter。

我的意思是片段的数量以及它们是否相似并不是始终要考虑的关键方面。片段是否动态也是关键。


所以说我有2个片段,片段A中有1个recyclerview,当我单击一个项目时,它更改了片段B的内容,说我做了fragB.setText(“ blablabla”)。我应该使用状态pagerthen吗?
Ced 2015年

不确定,但我会说是。只需同时尝试一下,将代码从一个代码更改为另一个代码确实非常简单快捷。
JDenais

@JDenais您确定这是正确的吗?我在使用FragmentPagerAdapterViewPager的活动中显示两个片段-每个片段都包含一个列表。我的第一个列表称为“所有报告”,第二个列表为“收藏夹报告”。在第一个列表中,如果我点击报告的星形图标,它将更新数据库以切换该报告的收藏状态。然后,我在第二个列表的用户界面中滑动,并成功看到了该报告。因此,也许实例被保留在内存中,但在某些情况下(例如我的),其内容实际上将对FragmentPagerAdapter进行更新
ban-geoengineering

14

FragmentPagerAdapter存储从适配器获取的先前数据,而FragmentStatePagerAdapter每次执行时从适配器获取新值。


4

FragmentStatePagerAdapter =在ViewPager中容纳大量片段。当该适配器对用户不可见时,它将破坏该片段,并且仅保留该片段的saveInstanceState以便进一步使用。这样,在使用动态片段的情况下,可以使用少量的内存并提供更好的性能。


1

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

FragmentStatePagerAdapter:当片段实例对用户不可见时(片段的保存状态除外),片段实例将被销毁。这导致仅使用少量的内存,并且对于处理较大的数据集可能很有​​用。当我们必须使用动态片段(如带有窗口小部件的片段)时应使用它们,因为它们的数据可以存储在saveInstanceState中,即使存在大量片段也不会影响性能。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.