ChatGPT解决这个技术问题 Extra ChatGPT

FragmentPagerAdapter 和 FragmentStatePagerAdapter 有什么区别?

FragmentPagerAdapterFragmentStatePagerAdapter 有什么区别?

关于 FragmentPagerAdapter Google 的指南说:

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

关于 FragmentStatePagerAdapter

当有大量页面时,此版本的寻呼机更有用,更像列表视图。当页面对用户不可见时,它们的整个片段可能会被销毁,只保留该片段的已保存状态。与 FragmentPagerAdapter 相比,这允许分页器保留与每个访问的页面相关联的内存少得多,但代价是在页面之间切换时可能会产生更多开销。

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

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

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

我认为只有 3 个片段使您有资格使用 FragmentPagerAdapter。这些片段的选项卡可能都同时可见。
这篇文章节省了我 5-6 个小时,因为我使用了错误类型的适配器
回答这个问题会引发另一个问题 stackoverflow.com/questions/9156406/…
FragmentPagerAdapterFragmentStatePagerAdapter 但什么是 FragmentStateAdapter

E
Emmanuel

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


我在 Fragment1 和 ListView 中有多个 Button 和 TextView,它们在 Fragment2 和 Fragment3 中动态生成项目。您认为使用 FragmentStatePagerAdapter 并将所有数据存储在 Activity 中,通过 Bundle 将其传递给 Fragments 是一个好主意吗?
@AlexMomotov Fragment 布局中的视图与 FragmentStatePagerAdapter 的选择没有任何关系。这里的问题是将被分页的片段数量。
所以基本上没有任何东西支持 FragmentPagerAdapter 使用它。
@Tomasz FragmentPagerAdapter 的优点是片段之间的切换可以更快,因为实际的 Fragment 对象不需要每次都重新构建。另一方面,这最终会使用更多的内存来保存内存中的片段对象。
我有 3 个选项卡/页面(每个都显示一个 WebView),所以使用了 FragmentPagerAdapter。但是,当我从第一页滑到最后一页时,最后一页仍然会被重绘。为了解决这个问题,我使用了 viewPager.setOffscreenPageLimit(2)
S
Steve

FragmentStatePagerAdapter:

使用 FragmentStatePagerAdapter,您不需要的 Fragment 将被销毁。提交事务以从您的 Activity 的 FragmentManager 中完全删除该 Fragment。

FragmentStatePagerAdapter 中的状态来自这样一个事实,即当它被销毁时,它将从 savedInstanceState 中保存您的 Fragment 的 Bundle。当用户导航回来时,新的 Fragment 将使用该 Fragment 的状态恢复。

片段页面适配器:

通过比较,FragmentPagerAdapter 什么都不做。当不再需要该片段时。FragmentPagerAdapter 在事务上调用 detach(Fragment) 而不是 remove(Fragment)。

这破坏了片段的视图,但在 FragmentManager 中保留了片段的实例。因此在 FragmentPagerAdapter 中创建的片段永远不会被破坏。


为什么你有2个答案?
将整个片段保存在内存中有什么好处?
@Tomek:如果下一个片段已经实例化(即FragmentPagerAdapter),当您滑动到它时它将准备好渲染,因此滑动动画会更流畅。使用 FragmentStatePagerAdapter,下一个 Fragment 实例可能在您滑动到它之前不存在,如果它是一个创建成本很高的大 Fragment,您可能会在动画中看到卡顿。这是性能与内存消耗的问题。
@Jared Burrows bcoz 一个是 AnswerText,适用于小而静态的答案,另一个是 AnswerStateText,适用于更大和动态的答案
L
Linh

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

FragmentStatePagerAdapter

转到 Fragment1(启动活动)

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

FragmentPagerAdapter

转到 Fragment1(启动活动)

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

结论:当 Fragment 被克服时,FragmentStatePagerAdapter 调用 onDestroy offscreenPageLimitFragmentPagerAdapter 没有。

注意:我认为我们应该将 FragmentStatePagerAdapter 用于具有大量页面的 ViewPager,因为它有利于性能。

offscreenPageLimit示例

如果我们转到 Fragment3,它销毁 Fragment1(或 Fragment5,如果有),因为 offscreenPageLimit = 1。如果我们设置 offscreenPageLimit > 1,它不会销毁。
如果在本例中,我们设置 offscreenPageLimit=4,则使用 FragmentStatePagerAdapterFragmentPagerAdapter 没有区别,因为 Fragment 从不调用 { 6} 和 onDestroy 当我们更改标签时

Github demo here


如此伟大的结论方式!
很好的解释
很好的解释。您说在有很多页面时使用 FragmentStatePagerAdapter 对性能有好处。你的意思是它对节省内存有好处吗?据我了解,目标是在可能有许多 Fragment 实例的情况下保留内存-因此性能是隐含的好处;明确的目标是保存记忆
J
JDenais

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

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

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


所以说我有 2 个片段,片段 A 中有 1 个 recyclerview,当我单击一个项目时,它会更改片段 B 的内容,比如我执行 fragB.setText("blablabla")。我应该使用状态寻呼机吗?
不确定,但我会说是的。只需尝试两者,无论如何将代码从一个更改为另一个非常简单快捷。
@JDenais 你确定这是正确的吗?我在使用 ViewPager 显示两个片段的活动中使用 FragmentPagerAdapter - 每个片段都包含一个列表。我的第一个列表称为“所有报告”,第二个列表是“最喜欢的报告”。在第一个列表中,如果我点击报告的星形图标,它会更新数据库以切换该报告的收藏状态。然后我扫过,我成功地在第二个列表的 UI 中看到了这个报告。所以也许这些实例被保存在内存中,但在某些情况下(例如,我的),内容实际上会为 FragmentPagerAdapter 更新
c
cyborg86pl

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


A
Ashish Dwivedi

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


f
foroogh Varmazyar

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

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


S
Sanam Yavarpor

根据文档:

管理每个片段的生命周期的标准 PagerAdapter 有两种类型:FragmentPagerAdapter 和 FragmentStatePagerAdapter。它们都适用于片段,但它们更适合不同的场景:

只要用户可以在片段之间导航,FragmentPagerAdapter 就会将片段存储在内存中。当片段不可见时,PagerAdapter 将分离它,但不会销毁它,因此片段实例在 FragmentManager 中保持活动状态。只有当 Activity 关闭时,它才会从内存中释放它。这可以使页面之间的过渡快速而流畅,但如果您需要很多片段,它可能会导致您的应用程序出现内存问题。

FragmentStatePagerAdapter 确保销毁用户看不到的所有片段,并仅将其保存的状态保留在 FragmentManager 中,因此得名。当用户导航回片段时,它将使用保存的状态恢复它。这个 PagerAdapter 需要的内存要少得多,但是在页面之间切换的过程可能会更慢。