Android Fragments sur la Backstack de prendre trop de mémoire

PROBLÈME:

J'ai une application Android qui permet à un utilisateur d'accéder à un profil utilisateur ViewProfileFragment. À l'intérieur de ViewProfileFragment un utilisateur peut cliquer sur une image qui va l'emmener à StoryViewFragment où les différents utilisateurs les photos montrent. Il est possible de cliquer sur une photo de profil qui les mènera vers une autre instance de ViewProfileFragment avec le nouveau profil de l'utilisateur. Si un utilisateur clique à plusieurs reprises sur des profils d'utilisateurs, clique sur une image qui mène à la galerie, puis clique sur un autre profil, les Fragments de la pile en mémoire rapidement causant la redoutable OutOfMemoryError. Voici un diagramme de flux de ce que je viens de décrire:

L'utilisateur clique sur Bob profil. À l'intérieur de Bob le profil de l'Utilisateur clique sur ImageA de l'emmener vers une galerie de photos de différents utilisateurs (y compris de Bob). L'utilisateur clique sur le profil de Sue, puis sur l'une de ses images - processus de répétitions, etc, etc.

UserA -> ViewProfileFragment
         StoryViewFragment -> ViewProfileFragment
                               StoryViewFragment -> ViewProfileFragment

Donc, comme vous pouvez le voir à partir d'un flux typique, il y a beaucoup de cas de ViewProfileFragment et StoryViewFragment entassent dans la backstack.

CODE

Je suis le chargement de ces fragments avec la logique suivante:

//from MainActivity
fm = getSupportFragmentManager();
ft = fm.beginTransaction();
ft.replace(R.id.activity_main_content_fragment, fragment, title);
ft.addToBackStack(title);

CE QUE J'AI ESSAYÉ

1) je suis plus particulièrement à l'aide FragmentTransaction replace de sorte que le onPause méthode sera déclenché lorsque l' replace prend place. À l'intérieur de onPause je suis en train d'essayer de libérer les ressources autant que je peux (comme l'effacement des données dans ListView adaptateurs, "invalide" sur les variables, etc), de sorte que lorsque le fragment n'est pas active fragment et poussé sur la backstack il n'y aura plus de mémoire libérée. Mais mes efforts pour libérer des ressources n'est qu'un succès partiel. Selon MAT j'ai encore beaucoup de mémoire consommée par GalleryFragment et ViewProfileFragment.

2) j'ai également supprimé l'appel à addToBackStack() mais, évidemment, qui offre une expérience utilisateur médiocre parce qu'ils ne peuvent pas traverser l'arrière (l'application se ferme lorsque l'utilisateur appuie sur le bouton de retour).

3) j'ai utilisé le TAPIS de trouver tous les objets que je prends beaucoup de place et j'ai traité avec ceux de diverses manières à l'intérieur de la onPause (et onResume) méthodes de libérer des ressources, mais ils sont encore considérables dans la taille.

Android Fragments sur la Backstack de prendre trop de mémoire

4) j'ai également écrit une boucle for dans les deux fragments onPause qui définit l'ensemble de mes ImageViews à null à l'aide de la logique suivante:

 for (int i=shell.getHeaderViewCount(); i<shell.getCount(); i++) {

     View h = shell.getChildAt(i);
     ImageView v = (ImageView) h.findViewById(R.id.galleryImage);
       if (v != null) {
           v.setImageBitmap(null);
       }
  }

myListViewAdapter.clear()

QUESTIONS

1) Suis-je surplombant une façon de permettre à un Fragment de rester sur la backstack mais aussi de libérer de ses ressources, de sorte que le cycle de .remplacer(fragment) ne consomme pas la totalité de ma mémoire?

2) Quelles sont les "meilleures pratiques" lorsqu'il est prévu qu'un grand nombre de Fragments peuvent être chargées sur la backstack? Comment un développeur de traiter correctement avec ce scénario? (Ou est la logique dans mon application intrinsèquement viciée et je suis juste de faire le mal?)

Toute aide dans la réflexion d'une solution à cela serait grandement apprécié.

  • Êtes-vous en utilisant le fragment de la méthode onPause?developer.android.com/reference/android/app/... je pense que vous devriez libérer les ressources bitmap associé avec le fragment sur la méthode onPause du fragment. Et pour améliorer la vitesse, spécialement si vos images sont chargées à partir de l'internet, de mettre en œuvre une image cache. Vous pouvez utiliser Image Universelle de Chargeur ou mettre en place votre propre.
  • Oui le <currentFragment>.onPause() est atteint lorsque le .replace(new_fragment) est émis. Je ne pense pas que c'est les images qui sont mon problème depuis que j'appelle listAdapter.clear() dans le onPause() méthode de suppression de toutes les données d'image. Ceux-ci sont chargés à l'aide de Pico.
  • Autant que je sache, le listAdapter.clear() ne pas libérer les ressources bitmap associé à l'ensemble du fragment... Au moins tous d'entre eux. Il ne supprime tous les éléments de la liste.
  • J'ai édité ma question pour montrer ce que j'ai dans mon onPause méthode pour aider à nettoyer les bitmaps (en appelant setImageBitmap(null) et de l'appel de .clear() sur la liste de l'adaptateur. Est-il une autre/une meilleure façon de libérer les images?
  • Jetez un oeil à ceci. Je pense que vous êtes déjà à la suite de ces étapes, mais juste au cas où vous ne le faites pas.
  • qui n'a pas de libérer les ressources utilisées par les bitmaps. Pour les libérer, vous devrez manuellement appel ((BitmapDrawable)ImageView.getDrawable()).getBitmap().le recyclage(). Mais alors vous aurez à charge les bitmaps de nouveau lors de la restauration de fragment, ou obtenir un crash.
  • Je suis sûr que c'est plus un problème avec mauvais flux de navigation, il est maître-détail et cyclique dans le même temps. Même si topicstarter libère toutes les ressources possibles, cadre de toujours garder trop de mémoire alloué pour suivre backstack de l'état et, éventuellement, que va provoquer le même incident, mais avec de l'utilisateur de l'effort appliqué
  • Salut @Drew. recycle() appel, il est seulement nécessaire sur la pré-nid d'appareils. En nid d'abeille de l'image bitmap de la mise en œuvre et de la collecte des déchets lui-même a changé, et il n'est pas nécessaire de nettoyer l'image de cette façon. Mais bitmap étaient toujours un peu délicat sur android os 😛 @MaxWorg vous êtes en train d'enregistrer les fragments dans la backstack?
  • Luis Encore, appelant recycle() est la seule façon de bataille OutOfMemoryError dans RecyclerViews/ListViews (avec juste bitmap montant) que j'ai trouvé de travail, même sur Lollipop API. Pas de.d'autres.chose.travaillé, et j'ai exeperimented avec toutes sortes de choses: l'image du chargeur de préférences, chargeur d'image des bibliothèques, quoi que ce soit. Juste comme ça.
  • dans mes tests (pour les applications que j'ai développées), j'ai réalisé une performance de la mémoire et du code compatible avec: -Mon propre cache Bitmap de mise en œuvre (améliore beaucoup la performance); -l'Appel à recycler, mais uniquement sur pré-nid d'appareils; -la Suppression de toutes les références inutiles lorsque l'activité/le fragment passe en premier plan, pour les rendre capables d'être nettoyé par le Garbage Collector. Il y a les principaux points que j'ai utilisé.
  • citant Android site du Développeur: On Android 2.3.3 (API level 10) and lower, using recycle() is recommended. If you're displaying large amounts of bitmap data in your app, you're likely to run into OutOfMemoryError errors. The recycle() method allows an app to reclaim memory as soon as possible.
  • Laissez-nous continuer cette discussion dans le chat.
  • Quelle solution avez-vous trouvé à la fin? Pouvez-vous donner un exemple de la façon dont vous êtes l'effacement des différentes ressources?

InformationsquelleAutor Max Worg | 2015-02-12