web-dev-qa-db-fra.com

Lorsqu'un fragment est remplacé et placé dans la pile arrière (ou supprimé), reste-t-il en mémoire?

Le comportement est-il similaire à la façon dont les activités fonctionnent? Par exemple, avec les activités, cela fonctionne comme ceci:

Activité A démarre Activité B, tandis que B est à l'écran, le système peut supprimer - A de la mémoire si le système en a besoin. En appuyant sur RETOUR, A sera recréé en mémoire comme s'il ne l'avait jamais quitté en premier lieu.

J'ai cherché une explication claire de ce qui se passe au niveau de la mémoire avec Fragments et je n'ai rien trouvé. Cela fonctionne-t-il de la même manière? Par exemple:

Activité C a Fragment F dans sa disposition. Ensuite, à un moment donné F est remplacé par Fragment G, mais F est conservé dans sa pile arrière.

F restera-t-il en mémoire jusqu'à ce que C soit tué ou peut-il être supprimé par le système au besoin?

Ce que je demande vraiment, c'est si je risque ou non de manquer de mémoire si j'ai une pile arrière de Fragments compliqués dans une seule Activité?

71
cottonBallPaws

Jetez un œil à ceci: BackStackRecord.Op.fragment

C'est ainsi que les fragments sont stockés dans la pile arrière. Notez la référence en direct, ni WeakReference ni SoftReference n'y sont utilisés.

Maintenant ceci: FragmentManagerImpl.mBackStack

C'est là que le gestionnaire stocke la pile arrière. Simple ArrayList, également, pas de WR ou SR.

Et enfin ceci: Activity.mFragments

C'est la référence au gestionnaire de fragments.

GC ne peut collecter que des objets qui n'ont pas de références actives (ne sont accessibles depuis aucun thread). Cela signifie, jusqu'à ce que votre activité soit détruite (et ainsi, la référence FragmentManager a disparu), GC ne pourra récupérer aucun des fragments de la pile arrière .

Notez que lorsque Activity est détruit et conserve son état (comme lorsque vous mettez l'appareil en mode paysage), il ne conserve pas les objets Fragment réels dans la pile, seuls leurs états - - Fragment.FragmentState objets, c'est-à-dire que les fragments réels dans la pile arrière sont recréés chaque fois que l'activité est recréée avec l'état conservé.

J'espère que cela t'aides.

[~ # ~] ps [~ # ~] Donc, en bref: Oui, vous pouvez manquer de mémoire en ajoutant Fragments pour sauvegarder la pile ainsi qu'en ajoutant trop de vues pour afficher la hiérarchie.

[~ # ~] upd [~ # ~] Compte tenu de votre exemple, [~ # ~] f [~ # ~] restera en mémoire jusqu'à ce que [~ # ~] c [~ # ~] soit tué. Si [~ # ~] c [~ # ~] est tué puis ressuscité avec une configuration différente - [~ # ~] f [~ # ~] sera également détruit et réincarné dans un objet différent. Donc, L'empreinte mémoire de [~ # ~] f [~ # ~] est d'environ jusqu'à [~ # ~] c [~ # ~] perd son état ou la pile arrière est effacée.

101
Ivan Bartsov

Je suis désolé de ne pas pouvoir vous fournir une source officielle d'informations, mais j'étais aussi curieux de voir ce qui allait se passer et j'ai décidé de le tester. Et selon mes tests, oui, vous courez le risque de manquer de mémoire.

J'ai dû ajouter une quantité incroyable de fragments (plus d'une centaine) dans une boucle for pour que le OutOfMemoryError se produise, mais c'est arrivé. Et en vérifiant mes journaux, j'ai pu voir que les méthodes onCreate() et onCreateView() étaient appelées plusieurs fois mais onSaveInstance(), onPause() et onDestroy n'a pas été appelé du tout.

Pour référence, voici comment j'ai ajouté les fragments au backstack:

getSupportFragmentManager().beginTransaction().add(R.id.scene_fragment_container, mSceneFragment).addToBackStack("FOOBAR").commit();

Et les fragments que j'ai ajoutés étaient assez simples: un ImageView, un EditText, un couple TextViews, un SeekBar et un ListView.

Mais à moins que vous ne conserviez une énorme quantité de données en mémoire, cela ne devrait pas être un problème.

Plus tard, j'ai essayé d'ajouter seulement 50 au backstack, tuant l'application et la redémarrant. Et comme je l'espérais/devinais, tous les fragments ont été restaurés (et les méthodes onSaveInstance() et onPause() appelées), donc l'implémentation de mon cycle de vie n'était pas le problème qui a causé le OutOfMemoryError pour tirer.

7
Beowulf Bjornson

De developer.Android.com/guide/topics/fundamentals/fragments.html

Un fragment doit toujours être intégré dans une activité et le cycle de vie du fragment est directement affecté par le cycle de vie de l'activité hôte. Par exemple, lorsque l'activité est suspendue, tous les fragments s'y trouvent également, et lorsque l'activité est détruite, tous les fragments le sont également. Cependant, pendant qu'une activité est en cours d'exécution (elle est dans l'état de reprise du cycle de vie), vous pouvez manipuler chaque fragment indépendamment, comme les ajouter ou les supprimer. Lorsque vous effectuez une telle transaction de fragment, vous pouvez également l'ajouter à une pile arrière gérée par l'activité - chaque entrée de pile arrière de l'activité est un enregistrement de la transaction de fragment qui s'est produite. La pile arrière permet à l'utilisateur d'annuler une transaction de fragment (naviguer vers l'arrière), en appuyant sur le bouton RETOUR.

4
Bill Gary

Oui, vous pouvez manquer de mémoire en créant trop de fragments en une seule activité. Les fragments ne seront détruits que lorsque l'activité contenant est.

1
Sid