В чем разница между FragmentPagerAdapter и FragmentStatePagerAdapter?

В чем разница между FragmentPagerAdapter и FragmentStatePagerAdapter?

О FragmentPagerAdapter Руководстве Google сказано:

Эта версия пейджера лучше всего подходит для использования, когда есть несколько обычно более статических фрагментов, которые нужно пролистать, например, набор вкладок. Фрагмент каждой страницы, которую посещает пользователь, будет храниться в памяти, хотя его иерархия представлений может быть уничтожена, когда она не видна. Это может привести к использованию значительного объема памяти, поскольку экземпляры фрагментов могут удерживать произвольный объем состояния. Для больших наборов страниц рассмотрите FragmentStatePagerAdapter.

А по поводу FragmentStatePagerAdapter:

Эта версия пейджера более полезна при большом количестве страниц и работает больше как представление списка. Когда страницы не видны пользователю, весь их фрагмент может быть уничтожен, сохраняя только сохраненное состояние этого фрагмента. Это позволяет пейджеру занимать гораздо меньше памяти, связанной с каждой посещаемой страницей, по сравнению с FragmentPagerAdapter за счет потенциально больших накладных расходов при переключении между страницами.

Так что у меня всего 3 фрагмента. Но все это отдельные модули с большим объемом данных.

Fragment1 обрабатывает некоторые данные (которые вводят пользователи) и передает их через действие в Fragment2, который представляет собой простой ListFragment. Fragment3 также ListFragment.

Итак, у меня следующие вопросы: какой адаптер мне следует использовать? FragmentPagerAdapter или FragmentStatePagerAdapter?


comment
Я думаю, что наличие только 3 фрагментов дает вам право использовать FragmentPagerAdapter. Скорее всего, все вкладки для этих фрагментов будут видны одновременно.   -  person IgorGanapolsky    schedule 28.05.2014
comment
этот пост сэкономил мне 5-6 часов, потому что я использую неправильный тип адаптера   -  person Nantaphop    schedule 11.08.2014
comment
Ответ на этот вопрос вызывает еще один вопрос: stackoverflow.com/questions/9156406/   -  person Piyush Kukadiya    schedule 19.03.2017
comment
есть FragmentPagerAdapter и FragmentStatePagerAdapter, но что такое FragmentStateAdapter?   -  person the_prole    schedule 18.12.2019


Ответы (7)


Как говорится в документации, подумайте об этом так. Если бы вы создавали приложение, подобное читалке книг, вам не захочется загружать в память сразу все фрагменты. Вы хотите загрузить и уничтожить Fragments по мере чтения пользователем. В этом случае вы будете использовать FragmentStatePagerAdapter. Если вы просто показываете 3 «вкладки», которые не содержат большого количества тяжелых данных (например, Bitmaps), то FragmentPagerAdapter может вам подойти. Также имейте в виду, что ViewPager по умолчанию загрузит в память 3 фрагмента. Первый Adapter, который вы упомянули, может разрушить View иерархию и повторно загрузить ее при необходимости, второй Adapter только сохраняет состояние Fragment и полностью уничтожает его, если пользователь затем возвращается на эту страницу, состояние извлекается.

person Emmanuel    schedule 11.09.2013
comment
У меня есть несколько кнопок и TextView в Fragment1 и ListView, которые динамически генерируют элементы во Fragment2 и Fragment3. Как вы думаете, стоит ли использовать FragmentStatePagerAdapter и хранить все данные в Activity, передавая их фрагментам через Bundle? - person AlexMomotov; 12.09.2013
comment
@AlexMomotov Представления в макете фрагмента не имеют ничего общего с выбором FragmentStatePagerAdapter. Вопрос в том, сколько фрагментов будет пролистано. - person IgorGanapolsky; 28.05.2014
comment
В общем, нет ничего в пользу FragmentPagerAdapter, чтобы использовать его. - person Tomasz Mularczyk; 02.07.2015
comment
@Tomasz Преимущество FragmentPagerAdapter в том, что переключение между фрагментами может быть намного быстрее, поскольку фактические Fragment объекты не нужно каждый раз перестраивать. С другой стороны, это привело бы к использованию большего объема памяти для хранения объектов фрагментов в памяти. - person Richard Le Mesurier; 30.11.2016
comment
У меня есть 3 вкладки / страницы (каждая из которых показывает WebView), поэтому я использовал FragmentPagerAdapter. Однако последняя страница все равно перерисовывается, когда я пролистываю на нее с первой страницы. Чтобы решить эту проблему, я использовал viewPager.setOffscreenPageLimit(2). - person ban-geoengineering; 27.07.2018
comment
@ ban-geoengineering, да, как уже писал Phan Van Linh, когда вы начнете активность, у вас будет создано только два фрагмента. Вы имеете в виду, что Fragment1 и Fragment3 перерисовываются при каждом смахивании к ним? - person CoolMind; 27.12.2018
comment
@CoolMind Если я правильно помню, да, последний / первый из трех фрагментов повторно отрисовывался каждый раз, когда я переходил к ним из первого / последнего фрагмента соответственно. - person ban-geoengineering; 28.12.2018
comment
@Emmanuel Какова цель переопределения containsItem и getItemId? Требуются ли эти переопределения, если новые списки передаются в реализацию FragmentStatePagerAdapter и вызываются notifyDataSetChanged? - person the_prole; 14.07.2021

FragmentStatePagerAdapter:

  • с FragmentStatePagerAdapter ваш ненужный фрагмент будет уничтожен. транзакция полностью удаляет фрагмент из FragmentManager вашей активности.

  • Состояние в FragmentStatePagerAdapter исходит из того факта, что он сохранит Bundle вашего фрагмента из savedInstanceState, когда он будет уничтожен. Когда пользователь перейдет назад, новый фрагмент будет восстановлен с использованием состояния фрагмента.

FragmentPagerAdapter:

  • Для сравнения FragmentPagerAdapter ничего подобного не делает. Когда фрагмент больше не нужен. FragmentPagerAdapter вызывает detach(Fragment) в транзакции вместо remove(Fragment).

  • Это уничтожает представление фрагмента, но оставляет экземпляр фрагмента живым в FragmentManager. Поэтому фрагменты, созданные в FragmentPagerAdapter, никогда не уничтожаются.

person Steve    schedule 29.07.2014
comment
Почему у вас 2 ответа? - person Jared Burrows; 17.10.2014
comment
какая польза от хранения в памяти целых фрагментов? - person Tomasz Mularczyk; 02.07.2015
comment
@Tomek: если следующий фрагмент уже создан (например, FragmentPagerAdapter), он будет готов к рендерингу, когда вы проведете по нему пальцем, поэтому анимация смахивания будет более плавной. С FragmentStatePagerAdapter следующий экземпляр фрагмента может не существовать, пока вы не проведете по нему пальцем, и если это большой фрагмент, создание которого дорого, вы можете увидеть заикание в анимации. Это вопрос производительности и потребления памяти. - person Dalbergia; 21.07.2015
comment
@Jared Burrows bcoz один - это просто AnswerText, который подходит для небольших и статичных ответов, а другой - AnswerStateText, который предназначен для более крупных и динамичных ответов - person Simple Fellow; 05.05.2018

Вот жизненный цикл журнала для каждого фрагмента в ViewPager, который имеет 4 фрагмента и offscreenPageLimit = 1 (default value)

FragmentStatePagerAdapter

Перейти к фрагменту 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

FragmentPagerAdapter

Перейти к фрагменту 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

Вывод: FragmentStatePagerAdapter вызов onDestroy, когда Фрагмент преодолен offscreenPageLimit, а FragmentPagerAdapter нет.

Примечание. Я думаю, что мы должны использовать FragmentStatePagerAdapter для ViewPager, у которых много страниц, потому что это хорошо для производительности.

Пример из offscreenPageLimit:

Если мы перейдем к Fragment3, он удалит Fragment1 (или Fragment5, если есть), потому что offscreenPageLimit = 1. Если мы установим offscreenPageLimit > 1, он не будет уничтожать.
Если в этом примере мы установим offscreenPageLimit=4, нет никакой разницы между использованием FragmentStatePagerAdapter или FragmentPagerAdapter, потому что Fragment никогда не вызывает onDestroyView и onDestroy, когда мы меняем вкладку

демонстрация Github здесь

person Linh    schedule 28.11.2017
comment
Такой отличный вывод! - person Rahul Rastogi; 28.10.2019
comment
хорошее объяснение - person gourav singhal; 27.11.2019
comment
Хорошее объяснение. Вы сказали, что использование FragmentStatePagerAdapter при большом количестве страниц улучшает производительность. Вы имели в виду, что это хорошо для экономии памяти? Насколько я понимаю, цель состоит в том, чтобы сохранить память в случае возможного большого количества экземпляров фрагментов, поэтому неявным преимуществом является производительность; явная цель - сохранить память - person Richard Miller; 11.04.2020

Что-то, что явно не сказано в документации или в ответах на этой странице (даже если это подразумевается @Naruto), заключается в том, что FragmentPagerAdapter не будет обновлять Фрагменты, если данные во Фрагменте изменятся, потому что он сохраняет Фрагмент в памяти.

Поэтому, даже если у вас есть ограниченное количество отображаемых фрагментов, если вы хотите иметь возможность обновлять свои фрагменты (скажем, например, вы повторно запускаете запрос для обновления listView во фрагменте), вам необходимо использовать FragmentStatePagerAdapter.

Я хочу сказать, что количество фрагментов и то, похожи они или нет, не всегда является ключевым аспектом, который следует учитывать. Также важно, являются ли ваши фрагменты динамическими.

person JDenais    schedule 20.06.2015
comment
Скажем, у меня есть 2 фрагмента, 1 recyclerview во фрагменте A, когда я нажимаю на элемент, он меняет содержимое фрагмента B, скажем, я делаю fragB.setText (blablabla). Тогда я должен использовать пейджер состояний? - person Ced; 03.12.2015
comment
Не уверен, но я бы сказал да. Просто попробуйте и то, и другое, в любом случае очень легко и быстро сменить код с одного на другой. - person JDenais; 04.12.2015
comment
@JDenais Вы уверены, что это правильно? Я использую FragmentPagerAdapter в своей деятельности, которая использует ViewPager для отображения двух фрагментов, где каждый фрагмент содержит список. Мой первый список называется «Все отчеты», а второй - «Избранные отчеты». В первом списке, если я коснусь значка звездочки для отчета, он обновит базу данных, чтобы переключить статус этого отчета в избранное. Затем я провожу пальцем по экрану и успешно вижу этот отчет в пользовательском интерфейсе второго списка. Так что, возможно, экземпляры хранятся в памяти, но в некоторых случаях (например, в моем) содержимое действительно обновляется нормально для FragmentPagerAdapter - person ban-geoengineering; 01.12.2016

FragmentPagerAdapter сохраняет предыдущие данные, полученные от адаптера, в то время как FragmentStatePagerAdapter принимает новое значение от адаптера каждый раз, когда он выполняется.

person vinay kumar    schedule 14.03.2015

FragmentStatePagerAdapter = Для размещения большого количества фрагментов в ViewPager. Поскольку этот адаптер уничтожает фрагмент, когда он не виден пользователю, и только сохраненное состояние экземпляра фрагмента сохраняется для дальнейшего использования. Таким образом, используется небольшой объем памяти и повышается производительность в случае динамических фрагментов.

person Dwivedi Ji    schedule 05.07.2017

FragmentPagerAdapter: фрагмент каждой страницы, которую посещает пользователь, будет сохранен в памяти, хотя представление будет уничтожено. Поэтому, когда страница снова станет видимой, представление будет воссоздано, но экземпляр фрагмента не будет воссоздан. Это может привести к использованию значительного объема памяти. FragmentPagerAdapter следует использовать, когда нам нужно сохранить весь фрагмент в памяти. FragmentPagerAdapter вызывает для транзакции detach (Fragment) вместо remove (Fragment).

FragmentStatePagerAdapter: экземпляр фрагмента уничтожается, когда он не виден пользователю, за исключением сохраненного состояния фрагмента. Это приводит к использованию только небольшого количества памяти и может быть полезно для обработки больших наборов данных. Должен использоваться, когда нам нужно использовать динамические фрагменты, такие как фрагменты с виджетами, поскольку их данные могут храниться в saveInstanceState. Кроме того, это не повлияет на производительность, даже если существует большое количество фрагментов.

person foroogh Varmazyar    schedule 21.01.2020