У чому різниця між FragmentPagerAdapter і FragmentStatePagerAdapter?


374

У чому різниця між FragmentPagerAdapterі FragmentStatePagerAdapter?

Про FragmentPagerAdapterпосібник Google йдеться:

Ця версія пейджера найкраще використовувати, коли є кілька типово більш статичних фрагментів, які підлягають проходці, наприклад, набір вкладок. Фрагмент кожної сторінки, яку відвідує користувач, зберігатиметься в пам’яті, хоча її ієрархія перегляду може бути зруйнована, коли її не буде видно. Це може призвести до використання значного обсягу пам'яті, оскільки екземпляри фрагментів можуть утримувати довільну кількість стану. Розгляньте про більші набори сторінок FragmentStatePagerAdapter.

І про FragmentStatePagerAdapter:

Ця версія пейджера є більш корисною, коли є велика кількість сторінок, які більше схожі на перегляд списку. Якщо сторінки не видно користувачеві, весь їх фрагмент може бути знищений, лише зберігаючи збережений стан цього фрагмента. Це дозволяє пейджеру утримувати набагато менше пам’яті, пов’язаної з кожною відвідуваною сторінкою, порівняно FragmentPagerAdapterз ціною потенційно більше накладних витрат при переході між сторінками.

Тож у мене всього 3 фрагменти. Але всі вони є окремими модулями з великим обсягом даних.

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

Тому мої запитання : Який адаптер я повинен використовувати? FragmentPagerAdapterабо FragmentStatePagerAdapter?


2
Я думаю, що лише 3 фрагменти дає змогу використовувати FragmentPagerAdapter. Вкладки для цих фрагментів, ймовірно, будуть видимі одночасно.
ІгорГанапольський

2
ця публікація врятувала мої 5-6 годин, тому що я використовую неправильний тип адаптера
Nantaphop

1
Відповідь на це питання проливає ще одне питання stackoverflow.com/questions/9156406 / ...
Piyush Kukadiya

є FragmentPagerAdapterі FragmentStatePagerAdapterале що є FragmentStateAdapter?
the_prole

Відповіді:


291

Як кажуть документи, подумайте про це так. Якби ви робили додаток, як читач книг, ви не захочете одразу завантажувати всі фрагменти в пам’ять. Ви хочете завантажити та знищити, Fragmentsяк читає користувач. У цьому випадку ви будете використовувати FragmentStatePagerAdapter. Якщо ви просто показуєте 3 "вкладки", які не містять багато важких даних (наприклад Bitmaps), то вони FragmentPagerAdapterможуть вам добре підійти. Також майте на увазі, що ViewPagerза замовчуванням завантажте в пам'ять 3 фрагменти. Перше, про що Adapterви згадуєте, може зруйнувати Viewієрархію та повторно завантажити його при необхідності, друге Adapterлише збереже стан Fragmentта повністю знищить його, якщо користувач потім повернеться на цю сторінку, стан буде відновлено.


У Fragment1 та ListView у мене є декілька кнопок і TextView, які динамічно генерують елементи у Fragment2 та Fragment3. Як ви вважаєте, чи є хорошою ідеєю використовувати FragmentStatePagerAdapter і зберігати всі дані в Активності, передаючи їх до фрагментів через пакет?
AlexMomotov

2
@AlexMomotov Перегляди у макеті фрагмента не мають нічого спільного з вибором FragmentStatePagerAdapter. Питання тут - кількість фрагментів, які будуть піддані підключення.
ІгорГанапольський

1
Так що в основному немає нічого на користь, FragmentPagerAdapterщоб ним користуватися.
Томаш Муларчик

3
Перевага @Tomasz полягає в FragmentPagerAdapterтому, що перемикання між фрагментами може бути набагато швидшим, оскільки фактичні Fragmentоб'єкти не потрібно щоразу перебудовувати. З іншого боку, це призвело б до використання більшої кількості пам'яті, що містить фрагменти об'єктів у пам'яті.
Річард Ле Месюр'є

У мене є 3 вкладки / сторінки (які показують WebView), тому я використовував FragmentPagerAdapter . Однак остання сторінка все-таки перемальовується, коли я переходжу на неї з першої сторінки. Для вирішення цього питання я використав viewPager.setOffscreenPageLimit(2).
заборона-геоінженерія

131
  • FragmentPagerAdapterзберігає весь фрагмент у пам'яті і може збільшити накладні витрати, якщо використовується велика кількість фрагментів ViewPager.

  • Навпаки, її брати, вони FragmentStatePagerAdapterзберігають лише збереженіInstanceState фрагментів і знищують усі фрагменти, коли вони втрачають фокус.

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

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

  • Коли я кажу, що весь фрагмент зберігається в пам'яті, це означає, що його екземпляри не будуть зруйновані, і це створить накладну пам'ять. Тому рекомендується використовувати FragmentPagerAdapterлише тоді, коли для них є невелика кількість фрагментів ViewPager.

  • Ще було б краще, якщо фрагменти статичні, оскільки вони не мали б великої кількості об'єктів, екземпляри яких зберігалися б.

Щоб бути детальніше,

FragmentStatePagerAdapter:

  • з FragmentStatePagerAdapter, ваш непотрібний фрагмент знищений. У трансакції здійснено повне видалення фрагмента з вашої діяльності FragmentManager.

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

FragmentPagerAdapter:

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

  • Це руйнує вигляд фрагмента, але залишає екземпляр фрагмента живим у., Тому FragmentManagerфрагменти, створені в FragmentPagerAdapter, ніколи не знищуються.


2
Чому у вас є 2 відповіді?
Джаред Берроуз

яка користь від збереження в пам’яті цілих фрагментів?
Томаш Муларчик

4
@Tomek: якщо наступний фрагмент вже створений (тобто FragmentPagerAdapter), він буде готовий для рендерінгу, коли ви перекладете його до нього, тому анімація пальців буде плавнішою. З FragmentStatePagerAdapter наступний екземпляр фрагмента може не існувати, поки ви не проведете його, і якщо це великий фрагмент, який дорого створити, ви можете побачити заїкання в анімації. Це питання продуктивності та споживання пам’яті.
Дальбергія

1
@Jred Burrows bcoz один - це лише 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тому, що фрагмент ніколи не викликає onDestroyViewіonDestroy коли ми змінюємо вкладку

Демонстрація Github тут


Такий чудовий спосіб висновку!
Рахул

приємне пояснення
gourav singhal

1
Приємне пояснення. Ви сказали, що використання FragmentStatePagerAdapter, коли багато сторінок, є хорошим для продуктивності. Ви мали на увазі, що це добре для збереження пам’яті? Як я розумію, мета полягає у збереженні пам'яті у випадку можливих безлічі екземплярів фрагмента - тому продуктивність - це неявна користь; чітка мета - збереження пам’яті
Хатзіл,

38

Те, що прямо не зазначено в документації або у відповідях на цій сторінці (навіть якщо це має на увазі @Naruto), це те, що FragmentPagerAdapter , що Фрагменти не буде оновлено, якщо дані у Фрагменті будуть змінені, оскільки він зберігає Фрагмент у пам'яті.

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

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


Так скажіть, у мене є 2 фрагменти, 1 рециркулятор в фрагменті A, коли я клацаю на елемент, він змінює вміст фрагмента B, скажімо, я роблю fragB.setText ("blablabla"). Я повинен використовувати стан pagerthen?
Ced

Не впевнено, але я б сказав так. Просто спробуйте і те, і інше - змінити код з одного на інший дуже просто і швидко.
JDenais

@JDenais Ви впевнені, що це правильно? Я використовую FragmentPagerAdapterу своїй діяльності, яка використовує ViewPager для показу двох фрагментів - де кожен фрагмент містить список. Мій перший список називається "Усі звіти", а другий - "Улюблені звіти". У першому списку, якщо я торкніться піктограми зірки для звіту, він оновлює базу даних, щоб переключити вибраний стан цього звіту. Потім я проведу пальцем поперек і успішно бачу цей звіт в інтерфейсі другого списку. Тож, можливо, екземпляри зберігаються в пам’яті, але в деяких випадках (наприклад, мій) вміст фактично буде оновлений для FragmentPagerAdapter
заборона-геоінженерія

14

FragmentPagerAdapterзберігає попередні дані, отримані з адаптера, при цьому FragmentStatePagerAdapterприймає нове значення з адаптера щоразу, коли воно виконується.


4

FragmentStatePagerAdapter = Для розміщення великої кількості фрагментів у ViewPager. Оскільки цей адаптер знищує фрагмент, коли він не видно користувачеві, і лише збереженийInstanceState фрагмента зберігається для подальшого використання. Таким чином використовується низький об'єм пам'яті та покращення продуктивності у випадку динамічних фрагментів.


1

FragmentPagerAdapter : фрагмент кожної сторінки, яку відвідує користувач, буде зберігатися в пам'яті, хоча представлення буде знищено. Отже, коли сторінка буде знову видима, перегляд буде відтворено, але екземпляр фрагмента не буде відтворений. Це може призвести до значного використання пам'яті. FragmentPagerAdapter слід використовувати, коли нам потрібно зберігати весь фрагмент у пам'яті. FragmentPagerAdapter викликає від'єднання (Fragment) транзакції замість видалення (Fragment).

FragmentStatePagerAdapter : екземпляр фрагмента знищується, коли він не видно Користувачеві, крім збереженого стану фрагмента. Це призводить до використання лише невеликої кількості пам'яті і може бути корисною для обробки великих наборів даних. Потрібно використовувати, коли нам доводиться використовувати динамічні фрагменти, як фрагменти з віджетами, оскільки їх дані можуть зберігатися в збереженомуInstanceState. Також це не вплине на продуктивність, навіть якщо є велика кількість фрагментів.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.