FragmentPagerAdapter和FragmentStatePagerAdapter之间有什么区别?

0s0u357o  于 2022-11-24  发布在  Android
关注(0)|答案(9)|浏览(182)

FragmentPagerAdapterFragmentStatePagerAdapter之间有什么区别?
关于FragmentPagerAdapter谷歌的指南说:
此版本的分页器最适合在有大量通常更为静态的片段(如一组选项卡)需要分页时使用。用户访问的每个页面的片段都将保存在内存中,虽然它的视图层次结构在不可见时可能会被破坏。这可能会导致使用大量的内存,因为片段示例可以保持任意数量的状态。对于较大的页面集,请考虑FragmentStatePagerAdapter
而关于FragmentStatePagerAdapter
此版本的页导航在页面数量较多时更有用,其工作方式更像列表视图。当页面对用户不可见时,它们的整个片段可能会被破坏,仅保持该片段的保存状态。与FragmentPagerAdapter相比,这允许寻呼机保持与每个被访问的寻呼相关联的少得多的存储器,代价是在得双曲余切值.
所以我只有3个片段。但是它们都是独立的模块,有大量的数据。
Fragment1处理一些数据(用户输入的数据),并通过activity将其传递到Fragment2Fragment2只是一个简单的ListFragmentFragment3也是一个ListFragment
"我的问题是“我应该使用哪种适配器?FragmentPagerAdapter还是FragmentStatePagerAdapter

ou6hu8tu

ou6hu8tu1#

片段分页器适配器:用户访问的每个页面的片段将被存储在内存中,尽管视图将被破坏。2所以当页面再次可见时,将重新创建视图,但不重新创建片段示例。这可能会导致使用大量内存。当需要在内存中存储整个片段时,应使用FragmentPagerAdapter。FragmentPagerAdapter调用detach(Fragment)而不是remove(Fragment)。
片段状态分页器适配器:当用户看不到片段示例时,除了片段的保存状态外,片段示例将被销毁。这会导致只使用少量内存,并有助于处理更大的数据集。应该在我们必须使用动态片段时使用,如带有小部件的片段,因为它们的数据可以存储在savedInstanceState中,而且即使存在大量片段也不会影响性能。

1mrurvl1

1mrurvl12#

根据doc:
有两种类型的标准PagerAdapter用于管理每个片段的生命周期:FragmentPagerAdapter和FragmentStatePagerAdapter。这两个适配器都可以很好地处理片段,但它们更适合于不同的情况:

  • 只要用户可以在片段之间导航,FragmentPagerAdapter就将片段存储在内存中。当片段不可见时,PagerAdapter将分离它,但不会破坏它,因此片段示例在FragmentManager中仍然有效。只有当Activity关闭时,它才会从内存中释放它。这可以使页面之间的转换快速而平稳。但如果您需要许多片段,则可能会导致应用程序出现内存问题。
  • FragmentStatePagerAdapter确保销毁用户看不到的所有片段,并且只在FragmentManager中保留它们的保存状态,因此得名。当用户导航回一个片段时,它将使用保存的状态还原它。此PagerAdapter需要的内存少得多,但在页面之间切换的过程可能会较慢。
vojdkbi0

vojdkbi03#

不了解技术细节,但根据我的经验:
如果你试图在一个片段中的viewPager中使用FragmentStatePagerAdapter,那么当你导航到另一个页面并返回时,你的子片段的选项菜单可能会混乱(或者根本不显示)。
就我所见,onCreateOptionsMenu的子片段直到用户点击一个标签才被调用。这可能是有意的,但对我来说是一场噩梦。
一些页面我来accros在绝望的搜索:
https://issuetracker.google.com/issues/37092407
OptionsMenu of Fragments in Viewpager showing each other's Buttons
Nested fragments in viewpager with different menus
PS:欢迎使用FragmentStatePagerAdapter对这个特定问题提出任何优雅的解决方案或建议

arknldoa

arknldoa4#

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

ojsjcaue

ojsjcaue5#

片段状态分页器适配器:

  • 对于FragmentStatePagerAdapter,您不需要的片段将被销毁。提交一个事务以从Activity的FragmentManager中完全删除该片段。
  • FragmentStatePagerAdapter中的状态来自于这样一个事实,即当片段被销毁时,它会从savedInstanceState中保存出片段的Bundle。当用户向后导航时,新片段将使用片段的状态进行恢复。
    片段分页器适配器:
  • 相比之下,FragmentPagerAdapter不做任何类似的事情。当不再需要片段时,FragmentPagerAdapter在事务上调用detach(Fragment)而不是remove(Fragment)
  • 这个destroy是fragment的视图,但是fragment的示例在FragmentManager中保持活动状态,因此在FragmentPagerAdapter中创建的fragment永远不会被销毁。
q8l4jmvw

q8l4jmvw6#

下面是ViewPager中每个片段的日志生命周期,其中包含4个片段和offscreenPageLimit = 1 (default value)

片段状态分页器适配器

转到片段1(启动活动)

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

转到片段2

Fragment3: onCreateView
Fragment3: onStart

转到片段3

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

转到片段4

Fragment2: onStop
Fragment2: onDestroyView
Fragment2: onDestroy

片段分页器适配器

转到片段1(启动活动)

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

转到片段2

Fragment3: onCreateView
Fragment3: onStart

转到片段3

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

转到片段4

Fragment2: onStop
Fragment2: onDestroyView

结论:当片段被offscreenPageLimit克服而FragmentPagerAdapter未被克服时,FragmentStatePagerAdapter调用onDestroy
注意:我认为我们应该将FragmentStatePagerAdapter用于包含大量页面的ViewPager,因为这样会提高性能。

offscreenPageLimit示例
如果我们转到Fragment3,它销毁Fragment1(或Fragment5,如果有),因为offscreenPageLimit = 1。如果我们设置offscreenPageLimit > 1,它将不会销毁。
如果在本例中,我们设置offscreenPageLimit=4,则使用FragmentStatePagerAdapterFragmentPagerAdapter没有区别,因为当我们更改tab时,Fragment从不调用onDestroyViewonDestroy
Github demo here

inb24sb2

inb24sb27#

在文档或本页的答案中没有明确说明的是(即使@Naruto暗示了这一点),如果Fragment中的数据发生变化,FragmentPagerAdapter不会更新Fragment,因为它将Fragment保留在内存中。
因此,即使要显示的片段数量有限,如果希望能够刷新片段(例如,重新运行查询以更新片段中的listView),也需要使用FragmentStatePagerAdapter。
我的观点是,片段的数量以及它们是否相似并不总是要考虑的关键方面,片段是否是动态的也是关键。

qfe3c7zg

qfe3c7zg8#

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

v8wbuo2f

v8wbuo2f9#

FragmentStatePagerAdapter =在ViewPager中容纳大量片段。由于此适配器会在用户看不到片段时将其销毁,因此只保留片段的savedInstanceState以供将来使用。这种方式使用的内存量较少,并且在动态片段的情况下可提供更好的性能。

相关问题