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

375

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

О FragmentPagerAdapterгугле говорит:

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

И о FragmentStatePagerAdapter:

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

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

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

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

AlexMomotov
источник
2
Я думаю, что наличие только 3 фрагментов дает вам право использовать FragmentPagerAdapter. Вкладки для этих фрагментов, вероятно, будут видны одновременно.
Игорь Ганапольский
2
этот пост сэкономил мне 5-6 часов, потому что я использую неправильный тип адаптера
Nantaphop
1
Ответ на этот вопрос выбрасывает еще один вопрос stackoverflow.com/questions/9156406/…
Пиюш Кукадия
есть FragmentPagerAdapterи FragmentStatePagerAdapterно что FragmentStateAdapter?
the_prole

Ответы:

292

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

Эммануэль
источник
У меня есть несколько кнопок и TextViews в Fragment1 и ListView, которые динамически генерируют элементы в Fragment2 и Fragment3. Считаете ли вы хорошей идеей использовать FragmentStatePagerAdapter и хранить все данные в Activity, передавая их фрагментам через Bundle?
AlexMomotov
2
@AlexMomotov Представления в макете фрагмента не имеют ничего общего с выбором FragmentStatePagerAdapter. Вопрос здесь - количество фрагментов, которые будут разбиты на страницы.
Игорь Ганапольский
1
Так что в принципе нет ничего в пользу того, FragmentPagerAdapterчтобы его использовать.
Томаш Муларчик
3
Преимущество @Tomasz FragmentPagerAdapterзаключается в том, что переключение между фрагментами может быть намного быстрее, поскольку реальные Fragmentобъекты не нужно каждый раз перестраивать. С другой стороны, это привело бы к использованию большего количества памяти, содержащей объекты фрагментов в памяти.
Ричард Ле Мезурье
У меня есть 3 вкладки / страницы (каждая из которых показывает веб-представление), поэтому я использовал FragmentPagerAdapter . Тем не менее, последняя страница все еще перерисовывается, когда я пролистываю к ней с первой страницы. Чтобы решить это, я использовал viewPager.setOffscreenPageLimit(2).
запрет геоинженерии
131
  • FragmentPagerAdapterсохраняет весь фрагмент в памяти и может увеличить объем памяти, если в нем используется большое количество фрагментов ViewPager.

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

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

  • Напротив, его родной брат FragmentPagerAdapterдолжен использоваться, когда нам нужно сохранить весь фрагмент в памяти.

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

  • Было бы еще лучше, если бы фрагменты были статическими, поскольку в них не было бы большого количества объектов, экземпляры которых будут сохранены.

Чтобы быть более подробно,

FragmentStatePagerAdapter:

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

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

FragmentPagerAdapter:

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

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

Стив
источник
2
Почему у вас есть 2 ответа?
Джаред Берроуз
какая польза от сохранения целых фрагментов в памяти?
Томаш Муларчик
4
@Tomek: если следующий фрагмент уже создан (например, FragmentPagerAdapter), он будет готов к визуализации, когда вы проведете по нему, поэтому анимация будет более плавной. С FragmentStatePagerAdapter следующий экземпляр фрагмента может не существовать, пока вы не проведете по нему пальцем, и если это большой фрагмент, создание которого стоит дорого, вы можете увидеть заикание в анимации. Это вопрос производительности и потребления памяти.
Дальбергия
1
@Jared Burrows, потому что один - это просто AnswerText, который хорош для небольших и статических ответов, а другой - AnswerStateText, который предназначен для больших и динамических ответов
Simple Fellow,
48

Вот журнал жизненного цикла каждого фрагмента, в 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

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

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

Пример из offscreenPageLimit:

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

Github демо здесь

Фан Ван Линь
источник
Такой отличный способ заключения!
Рахул Растоги
Хорошее объяснение
Гурав Сингхал
1
Хорошее объяснение. Вы сказали, что использование FragmentStatePagerAdapter при большом количестве страниц хорошо для производительности. Вы имели в виду, что это хорошо для экономии памяти? Насколько я понимаю, цель состоит в том, чтобы сохранить память на случай возможного множества экземпляров фрагмента, поэтому производительность является неявным преимуществом; явная цель - сохранить память
Хатзил
38

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

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

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

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

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

Винай Кумар
источник
4

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

Двиведи Джи
источник
1

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

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

foroogh.Varmazyar
источник