Picasso: de mémoire
J'ai un RecyclerView
présenter plusieurs images à l'aide de Picasso
. Après avoir fait défiler un certain temps en haut et en bas de l'application est à court de mémoire avec des messages comme ceci:
E/dalvikvm-heap﹕ Out of memory on a 3053072-byte allocation.
I/dalvikvm﹕ "Picasso-/wp-content/uploads/2013/12/DSC_0972Small.jpg" prio=5 tid=19 RUNNABLE
I/dalvikvm﹕ | group="main" sCount=0 dsCount=0 obj=0x42822a50 self=0x59898998
I/dalvikvm﹕ | sysTid=25347 nice=10 sched=0/0 cgrp=apps/bg_non_interactive handle=1500612752
I/dalvikvm﹕ | state=R schedstat=( 10373925093 843291977 45448 ) utm=880 stm=157 core=3
I/dalvikvm﹕ at android.graphics.BitmapFactory.nativeDecodeStream(Native Method)
I/dalvikvm﹕ at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:623)
I/dalvikvm﹕ at com.squareup.picasso.BitmapHunter.decodeStream(BitmapHunter.java:142)
I/dalvikvm﹕ at com.squareup.picasso.BitmapHunter.hunt(BitmapHunter.java:217)
I/dalvikvm﹕ at com.squareup.picasso.BitmapHunter.run(BitmapHunter.java:159)
I/dalvikvm﹕ at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:390)
I/dalvikvm﹕ at java.util.concurrent.FutureTask.run(FutureTask.java:234)
I/dalvikvm﹕ at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1080)
I/dalvikvm﹕ at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:573)
I/dalvikvm﹕ at java.lang.Thread.run(Thread.java:841)
I/dalvikvm﹕ at com.squareup.picasso.Utils$PicassoThread.run(Utils.java:411)
I/dalvikvm﹕ [ 08-10 18:48:35.519 25218:25347 D/skia ]
--- decoder->decode returned false
Les choses que je remarque en cours de débogage:
- Lors de l'installation de l'application sur un téléphone ou un périphérique virtuel, les images sont chargées sur le réseau, ce qui est la façon dont il est censé être. Ceci est perçu par le triangle rouge dans le coin supérieur gauche de l'image.
- Lors du défilement de sorte que les images sont rechargées, elles sont lues à partir du disque. Ceci est perçu par le triangle bleu dans le coin supérieur gauche de l'image.
- Lors du défilement de plus, certaines images sont chargées à partir de la mémoire, comme on le voit par un triangle vert dans le coin supérieur gauche.
- Après le défilement, la mémoire exception se produit et le chargement s'arrête. Seulement l'image d'espace réservé est indiqué sur les images qui ne sont pas actuellement conservé dans la mémoire, alors que ceux de la mémoire sont affichés correctement avec un triangle vert.
Ici est une image de l'échantillon. Il est assez grand, mais je l'utilise fit()
à réduire l'empreinte mémoire de l'application.
Donc mes questions sont:
- Ne pas les images être rechargé à partir du disque lorsque la mémoire cache
est-il plein? - Les images sont tout simplement trop grand? De combien de mémoire puis-je
s'attendre à une, disons 0,5 MO image, à consommer lors du décodage? - Est-il quelque chose de mal ou peu dans mon code ci-dessous?
De la configuration de la statique Picasso exemple lors de la création de la Activity
:
private void setupPicasso()
{
Cache diskCache = new Cache(getDir("foo", Context.MODE_PRIVATE), 100000000);
OkHttpClient okHttpClient = new OkHttpClient();
okHttpClient.setCache(diskCache);
Picasso picasso = new Picasso.Builder(this)
.memoryCache(new LruCache(100000000)) //Maybe something fishy here?
.downloader(new OkHttpDownloader(okHttpClient))
.build();
picasso.setIndicatorsEnabled(true); //For debugging
Picasso.setSingletonInstance(picasso);
}
À l'aide de la statique Picasso exemple, dans mon RecyclerView.Adapter
:
@Override
public void onBindViewHolder(RecipeViewHolder recipeViewHolder, int position)
{
Picasso.with(mMiasMatActivity)
.load(mRecipes.getImage(position))
.placeholder(R.drawable.picasso_placeholder)
.fit()
.centerCrop()
.into(recipeViewHolder.recipeImage); //recipeImage is an ImageView
//More...
}
La ImageView
dans le fichier XML:
<ImageView
android:id="@+id/mm_recipe_item_recipe_image"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:paddingBottom="2dp"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:clickable="true"
/>
Mise à jour
Il semble que le défilement de la RecyclerView
fait continuellement l'allocation de mémoire s'accroître indéfiniment. J'ai fait un test RecyclerView
dépouillé vers le bas pour correspondre à la la documentation officielle, à l'aide d'une seule image pour 200 CardView
s avec un ImageView
, mais le problème persiste. La plupart des images sont chargées à partir de la mémoire (en vert) et le défilement est fluide, mais sur chaque dixième ImageView
de charger l'image à partir du disque (en bleu). Lorsque l'image est chargée à partir d'un disque, d'une allocation de mémoire est effectuée, ainsi, d'augmenter l'allocation sur le tas et donc le segment lui-même.
J'ai essayé de l'enlever de ma propre installation de la global Picasso
instance et en utilisant la valeur par défaut à la place, mais les problèmes sont les mêmes.
J'ai fait un contrôle avec l'Appareil Android, Moniteur, voir l'image ci-dessous. C'est pour un Galaxy S3. Chacun des allocations de fait lorsqu'une image est chargé à partir du disque peut être vu à droite, sous "nombre d'allocations par la taille". La taille est légèrement différente pour chaque allocation de l'image, ce qui est aussi bizarre. En appuyant sur "Provoquer GO" rend le plus à droite de l'allocation de 4,7 MO en aller.
Le comportement est le même pour les périphériques virtuels. L'image ci-dessous montre pour un Nexus 5 AVD. Ici aussi, la plus grande répartition (10,6 MB) disparaît lorsque vous appuyez sur "Provoquer GO".
De plus, voici des images de l'allocation de mémoire les emplacements et les fils de l'Appareil Android Moniteur. La réapparition des allocations sont effectuées dans le Picasso
threads alors que l'on a supprimé avec Cause GB
est fait sur le thread principal.
- Je suis d'avoir exactement le même problème, Même avec seulement 25 recycler les éléments, si j'ai faites défiler vers le haut et vers le bas en permanence il plante avec de la mémoire exception.
Vous devez vous connecter pour publier un commentaire.
Je ne suis pas sûr
fit()
fonctionne avecandroid:adjustViewBounds="true"
. Selon certains dernières questions il semble être problématique.Quelques recommandations:
resize()
méthodeandroid:adjustViewBounds="true"
que gâché les choses. Retrait qui fait disparaître les problèmes instantanément. Je suppose une hauteur fixe pourrait être dans l'ordre en tant que bien de sorte que leImageViews
sont certains d'être de taille égale. Et je vais peut-être donner Glisse essayer parfois ainsi. Cheers!Je dirais que c'est en effet fish - vous donnons la
LruCache
100 mo d'espace. Bien que tous les appareils sont différents, cela va être au niveau ou au-dessus de la limite pour certains appareils, et de garder à l'esprit que ce n'est que leLruCache
, ne tenant pas compte, cependant, beaucoup d'espace de tas le reste de votre application exige. Ma conjecture est que c'est la cause directe de l'exception - vous racontez l'LruCache
qu'il est autorisé à obtenir beaucoup plus grand qu'il ne devrait l'être.Je voudrais réduire ce chiffre à quelque chose comme 5 MO d'abord prouver la théorie, et puis, avec l'expérience progressivement des valeurs plus élevées sur les périphériques cibles. Vous pouvez également interroger le dispositif pour déterminer la quantité d'espace dont il dispose et de définir cette valeur par programmation si vous le souhaitez. Enfin, il y a le
android:largeHeap="true"
attribut que vous pouvez ajouter à votre manifeste, mais j'ai rassemblé ce n'est généralement pas une bonne pratique.Vos images sont en effet de gros donc je suggère de réduire ceux aussi bien. Gardez à l'esprit que même si vous êtes coupant, ils ont besoin temporairement d'être chargé en mémoire à leur taille réelle.
RecyclerView
, les images sont constamment à la lecture (à partir du disque). Cela provoque le tas à se développer (!) et quand je le fais pour une assez longue durée, elle atteint son maximum (64 MO sur mon appareil de test). Pouvez-vous voir des autres bizarreries dans mon code qui peut en être la cause?onViewRecycled
événement sur votre carte? J'ai augmenté mes implémentations performances en appelantPicasso.with(...).cancelRequest(IMAGEVIEW TO BE RECYCLED);
avec picasso, vous pouvez résoudre le problème en utilisant sa propriété
comme:
vous avez besoin de redimensionner l'image.
Je viens de faire une classe Singleton à LoadImages. Le problème était que j'utilisais trop de Picasso objets créés avec trop de Picasso.Générateur de rapports. Voici mon oeuvre:
Ensuite, vous créez une
ImageToLoad
classe qui détient le ImageView, Url, espace Réservé et d'Erreur de l'espace Réservé.