Quelle est la différence entre FragmentPagerAdapter et FragmentStatePagerAdapter?

375

Quelle est la difference entre FragmentPagerAdapteret FragmentStatePagerAdapter?

À propos FragmentPagerAdapterdu guide de Google dit:

Cette version du pageur est préférable pour une utilisation lorsqu'il existe une poignée de fragments généralement plus statiques à parcourir, comme un ensemble d'onglets. Le fragment de chaque page visitée par l'utilisateur sera conservé en mémoire, bien que sa hiérarchie de vues puisse être détruite lorsqu'elle n'est pas visible. Cela peut entraîner l'utilisation d'une quantité importante de mémoire car les instances de fragments peuvent conserver une quantité d'état arbitraire. Pour de plus grands ensembles de pages, considérez FragmentStatePagerAdapter.

Et sur FragmentStatePagerAdapter:

Cette version du pager est plus utile quand il y a un grand nombre de pages, fonctionnant plus comme une vue de liste. Lorsque les pages ne sont pas visibles pour l'utilisateur, leur fragment entier peut être détruit, ne conservant que l'état enregistré de ce fragment. Cela permet au téléavertisseur de conserver beaucoup moins de mémoire associée à chaque page visitée par rapport FragmentPagerAdapterau coût potentiellement plus élevé lors du basculement entre les pages.

Je n'ai donc que 3 fragments. Mais tous sont des modules séparés avec une grande quantité de données.

Fragment1gère certaines données (que les utilisateurs saisissent) et les transmet via une activité Fragment2, ce qui est simple ListFragment. Fragment3est aussi un ListFragment.

Mes questions sont donc les suivantes : quel adaptateur dois-je utiliser? FragmentPagerAdapterou FragmentStatePagerAdapter?

AlexMomotov
la source
2
Je pense qu'avoir seulement 3 fragments vous permet d'utiliser FragmentPagerAdapter. Les onglets de ces fragments seront probablement tous visibles simultanément.
IgorGanapolsky
2
ce message a sauvé mes 5-6 heures car j'utilise un mauvais type d'adaptateur
Nantaphop
1
La réponse à cette question lance une autre question stackoverflow.com/questions/9156406/…
Piyush Kukadiya
il y a FragmentPagerAdapteret FragmentStatePagerAdapterqu'est-ce que c'est FragmentStateAdapter?
the_prole

Réponses:

292

Comme le disent les docs, pensez-y de cette façon. Si vous deviez faire une application comme un lecteur de livre, vous ne voudrez pas charger tous les fragments en mémoire à la fois. Vous souhaitez charger et détruire Fragmentspendant que l'utilisateur lit. Dans ce cas, vous utiliserez FragmentStatePagerAdapter. Si vous affichez simplement 3 "onglets" qui ne contiennent pas beaucoup de données lourdes (comme Bitmaps), cela FragmentPagerAdapterpourrait vous convenir. Gardez également à l'esprit que ViewPagerpar défaut, 3 fragments seront chargés en mémoire. Le premier que Adaptervous mentionnez peut détruire la Viewhiérarchie et la recharger si nécessaire, le second Adaptern'enregistre que l'état du Fragmentet le détruit complètement, si l'utilisateur revient ensuite sur cette page, l'état est récupéré.

Emmanuel
la source
J'ai plusieurs boutons et TextViews dans Fragment1 et ListView qui génèrent des éléments dynamiquement dans Fragment2 et Fragment3. Pensez-vous que c'est une bonne idée d'utiliser FragmentStatePagerAdapter et de stocker toutes les données dans Activity, en les transmettant à Fragments via Bundle?
AlexMomotov
2
@AlexMomotov Les vues dans la disposition du fragment n'ont rien à voir avec le choix de FragmentStatePagerAdapter. La question ici est la quantité de fragments qui seront paginés.
IgorGanapolsky
1
Donc, fondamentalement, il n'y a rien en faveur de l' FragmentPagerAdapterutiliser.
Tomasz Mularczyk
3
@Tomasz a pour avantage FragmentPagerAdapterque la commutation entre les fragments pourrait être beaucoup plus rapide, car les Fragmentobjets réels n'ont pas besoin d'être reconstruits à chaque fois. D'un autre côté, cela finirait par utiliser plus de mémoire contenant les objets fragmentés en mémoire.
Richard Le Mesurier
J'ai 3 onglets / pages (qui montrent chacun une WebView), j'ai donc utilisé FragmentPagerAdapter . Cependant, la dernière page est toujours redessinée lorsque je glisse dessus depuis la première page. Pour résoudre ce problème, j'ai utilisé viewPager.setOffscreenPageLimit(2).
ban-geoengineering
131
  • FragmentPagerAdapterstocke le fragment entier en mémoire et pourrait augmenter la surcharge de mémoire si une grande quantité de fragments est utilisée dans ViewPager.

  • Au contraire, son frère, FragmentStatePagerAdapterne stocke que l'état sauvegardéInstanceState et détruit tous les fragments lorsqu'ils perdent le focus.

  • Par conséquent, FragmentStatePagerAdapterdoit être utilisé lorsque nous devons utiliser des fragments dynamiques, comme des fragments avec des widgets, car leurs données pourraient être stockées dans le savedInstanceState.Aussi cela n'affectera pas les performances même s'il y a un grand nombre de fragments.

  • Au contraire, son frère FragmentPagerAdapterdevrait être utilisé lorsque nous devons stocker le fragment entier en mémoire.

  • Quand je dis que le fragment entier est gardé en mémoire, cela signifie que ses instances ne seront pas détruites et créeraient une surcharge de mémoire. Par conséquent, il est conseillé de n'utiliser FragmentPagerAdapterque lorsque le nombre de fragments est faible ViewPager.

  • Ce serait encore mieux si les fragments sont statiques, car ils n'auraient pas une grande quantité d'objets dont les instances seraient stockées.

Pour être plus détaillé,

FragmentStatePagerAdapter:

  • avec FragmentStatePagerAdapter, votre fragment inutile est détruit. Une transaction est engagée pour supprimer complètement le fragment de votre activité FragmentManager.

  • L'état dans FragmentStatePagerAdaptervient du fait qu'il sauvera votre fragment Bundlede savedInstanceStatequand il est détruit. Lorsque l'utilisateur revient, le nouveau fragment sera restauré en utilisant l'état du fragment.

FragmentPagerAdapter:

  • Par comparaison FragmentPagerAdapterne fait rien de tel.Lorsque le fragment n'est plus nécessaire. FragmentPagerAdapterappelle detach(Fragment)la transaction au lieu de remove(Fragment).

  • Cela détruit la vue du fragment mais laisse l'instance du fragment vivante dans le FragmentManager.so les fragments créés dans le FragmentPagerAdapterne sont jamais détruits.

Steve
la source
2
Pourquoi avez-vous 2 réponses?
Jared Burrows
quel est l'avantage de garder des fragments entiers en mémoire?
Tomasz Mularczyk
4
@Tomek: si le prochain fragment est déjà instancié (c'est-à-dire FragmentPagerAdapter), il sera prêt à être rendu lorsque vous y glisserez, donc l'animation de glissement sera plus fluide. Avec FragmentStatePagerAdapter, l'instance de fragment suivante peut ne pas exister tant que vous n'y avez pas glissé, et s'il s'agit d'un gros fragment coûteux à créer, vous pouvez voir un bégaiement dans l'animation. C'est une question de performance par rapport à la consommation de mémoire.
Dalbergia
1
@Jared Burrows bcoz l'un est simplement AnswerText qui est bon pour les réponses petites et statiques et l'autre est AnswerStateText qui est pour les réponses plus grandes et dynamiques
Simple Fellow
48

Voici un cycle de vie du journal de chaque fragment dans ViewPagerlequel ont 4 fragments etoffscreenPageLimit = 1 (default value)

FragmentStatePagerAdapter

Allez à Fragment1 (activité de lancement)

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

Aller à Fragment2

Fragment3: onCreateView
Fragment3: onStart

Allez au Fragment3

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

Allez à Fragment4

Fragment2: onStop
Fragment2: onDestroyView
Fragment2: onDestroy

FragmentPagerAdapter

Allez à Fragment1 (activité de lancement)

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

Aller à Fragment2

Fragment3: onCreateView
Fragment3: onStart

Allez au Fragment3

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

Allez à Fragment4

Fragment2: onStop
Fragment2: onDestroyView

Conclusion : FragmentStatePagerAdapterappelez onDestroyquand le Fragment est surmonté offscreenPageLimitalors que FragmentPagerAdapternon.

Remarque : je pense que nous devrions utiliser FragmentStatePagerAdapterpour un ViewPagerqui a beaucoup de page car il sera bon pour les performances.

Exemple de offscreenPageLimit:

Si nous allons à Fragment3, il sera DETROY Fragment1 (ou si Fragment5 ont) parce que offscreenPageLimit = 1. Si nous le réglons, offscreenPageLimit > 1il ne sera pas détruit.
Si dans cet exemple, nous définissons offscreenPageLimit=4, il n'y a pas de différence entre utiliser FragmentStatePagerAdapterou FragmentPagerAdapterparce que Fragment n'appelle jamais onDestroyViewet onDestroyquand nous changeons d'onglet

Démo Github ici

Phan Van Linh
la source
Une si belle façon de conclure!
Rahul Rastogi
belle explication
gourav singhal
1
Belle explication. Vous avez dit que l'utilisation de FragmentStatePagerAdapter lorsque vous avez beaucoup de pages est bonne pour les performances. Vouliez-vous dire qu'il est bon pour économiser de la mémoire? Le but, si je comprends bien, est de préserver la mémoire en cas de nombreuses instances de Fragment possibles - donc la performance est l'avantage implicite; l'objectif explicite est de préserver la mémoire
Hatzil
38

Quelque chose qui n'est pas dit explicitement dans la documentation ou dans les réponses sur cette page (même si cela est implicite par @Naruto), est que FragmentPagerAdaptercela ne mettra pas à jour les fragments si les données dans le fragment changent parce qu'il garde le fragment en mémoire.

Ainsi, même si vous avez un nombre limité de fragments à afficher, si vous souhaitez pouvoir actualiser vos fragments (par exemple, vous réexécutez la requête pour mettre à jour la listView dans le fragment), vous devez utiliser FragmentStatePagerAdapter.

Tout ce que je veux dire ici, c'est que le nombre de fragments et leur similitude ne sont pas toujours l'aspect clé à considérer. Que vos fragments soient dynamiques ou non est également essentiel.

JDenais
la source
Donc disons que j'ai 2 fragments, 1 recyclerview dans le fragment A, quand je clique sur un élément, cela change le contenu du fragment B, disons que je fais fragB.setText ("blablabla"). Je devrais utiliser l'état pagerthen?
Ced
Pas certain mais je dirais oui. Essayez simplement les deux, il est de toute façon très simple et rapide de changer votre code de l'un à l'autre.
JDenais
@JDenais Êtes-vous sûr que c'est correct? J'utilise FragmentPagerAdapterdans mon activité qui utilise un ViewPager pour afficher deux fragments - où chaque fragment contient une liste. Ma première liste est appelée "Tous les rapports" et la deuxième liste est "Rapports favoris". Dans la première liste, si je tape sur l'icône en forme d'étoile pour un rapport, il met à jour la base de données pour basculer le statut favori de ce rapport. Je glisse ensuite à travers et je vois avec succès ce rapport dans l'interface utilisateur de la deuxième liste. Alors peut-être que les instances sont conservées en mémoire mais dans certains cas (par exemple, le mien) le contenu sera effectivement mis à jour correctement pour FragmentPagerAdapter
ban-geoengineering
14

FragmentPagerAdapterstocke les données précédentes extraites de l'adaptateur tout en FragmentStatePagerAdapterprenant la nouvelle valeur de l'adaptateur à chaque exécution.

vinay kumar
la source
4

FragmentStatePagerAdapter = Pour accueillir un grand nombre de fragments dans ViewPager. Étant donné que cet adaptateur détruit le fragment lorsqu'il n'est pas visible pour l'utilisateur et seul le instance de sauvegarde du fragment est conservé pour une utilisation ultérieure. De cette façon, une faible quantité de mémoire est utilisée et de meilleures performances sont fournies en cas de fragments dynamiques.

Dwivedi Ji
la source
1

FragmentPagerAdapter : le fragment de chaque page visitée par l'utilisateur sera stocké en mémoire, bien que la vue soit détruite. Ainsi, lorsque la page est à nouveau visible, la vue est recréée mais l'instance de fragment n'est pas recréée. Cela peut entraîner une quantité importante de mémoire utilisée. FragmentPagerAdapter doit être utilisé lorsque nous devons stocker le fragment entier en mémoire. FragmentPagerAdapter appelle detach (Fragment) sur la transaction au lieu de remove (Fragment).

FragmentStatePagerAdapter : l'instance de fragment est détruite lorsqu'elle n'est pas visible pour l'utilisateur, à l'exception de l'état enregistré du fragment. Cela se traduit par l'utilisation d'une petite quantité de mémoire et peut être utile pour gérer des ensembles de données plus volumineux. Doit être utilisé lorsque nous devons utiliser des fragments dynamiques, comme des fragments avec des widgets, car leurs données pourraient être stockées dans le sharedInstanceState. De plus, cela n'affectera pas les performances même s'il y a un grand nombre de fragments.

foroogh.Varmazyar
la source