Question

Il s'agit d'un scénario très courant: afficher des images dans un ListView devant être téléchargées à partir d'Internet.

À l'heure actuelle, j'ai une sous-classe personnalisée de ArrayAdapter que j'utilise pour ListView. Dans mon implémentation getView () de ArrayAdapter, je crée un thread séparé pour charger une image. Une fois le chargement terminé, il recherche l'image ImageView appropriée et définit l'image à l'aide de ImageView.setImageDrawable (). La solution que j'ai utilisée ressemble donc beaucoup à celle-ci: Chargement paresseux d'images dans ListView

Le problème que je rencontre est que dès que j'appelle setImageDrawable () sur ImageView, ListView actualise en quelque sorte toutes les lignes actuellement visibles de la liste! Il en résulte une sorte de boucle infinie:

  1. getView () est appelé
  2. le fil est créé pour charger l'image
  3. l'image est chargée; setImageDrawable () est appelé sur ImageView
  4. ListView le récupère pour une raison quelconque et se rafraîchit lui-même
  5. Pour que ListView se régénère, getView () est appelé pour chaque ligne visible. Nous revenons donc à l'étape 1 et tout se répète

Pour autant que je sache, la solution proposée dans "Android - Comment puis-je charger paresseusement des images dans ListView " (voir lien ci-dessus) ne fonctionne tout simplement pas. Cela peut sembler être le cas, mais cela fonctionnera très lentement car, en arrière-plan, il continue de recharger les lignes actuellement visibles.

Quelqu'un l'a-t-il déjà rencontré et / ou a-t-il trouvé une solution à ce problème?

Était-ce utile?

La solution

Dans la solution liée, fetchDrawableOnThread () ne doit être appelé que si la vue ne contient pas déjà le bon dessin.

Une vue ne peut pas être dessinée si getDrawable () renvoie la valeur null.

Si vous réutilisez des logements, vous vous devez d’aller plus loin et de gérer l’état. Si vos vues ont une variable membre stockant l'URL et un booléen indiquant si elle est chargée, il serait facile de savoir s'il faut appeler fetchDrawableOnThread () ou non, par exemple.

Je supposerais que le toString () du dessinable donne le chemin à partir duquel l'image a été chargée. (Si ce n'est pas le cas, vous pouvez sous-classer le dessinable retourné pour qu'il en soit ainsi). Dans ce cas, vous pouvez éviter le booléen décrit ci-dessus et simplement faire une comparaison afin de déterminer si le tirage est correct ou s'il faut chercher un remplaçant.

De plus, votre getView () sur une ligne visible doit permettre de décharger celles qui ne sont plus visibles, afin d'éviter l'épuisement de la mémoire. Une finesse serait de déplacer les images qui ne sont plus visibles vers des références logicielles (afin qu’elles soient déchargées lorsqu’il faut de la mémoire) sous la forme d’une autre affiche sur le fil de discussion original.

Autres conseils

J'ai utilisé le code dans le lien suivant: une autre question de stackoverflow

J'ai apporté de petites modifications afin de résoudre le problème de la vue de recyclage.i définir l'URL de l'image sur Tag de l'imageview dans l'adaptateur. Le code suivant contient ma solution qui résout le problème de recyclage:

public void fetchDrawableOnThread(final String urlString, final ImageView imageView,Drawable drw) {

    imageView.setImageDrawable(drw);//drw is default image
    if (drawableMap.containsKey(urlString)) {
        if(imageView.getTag().toString().equals(urlString))
        {
            imageView.setImageBitmap(drawableMap.get(urlString));
            imageView.invalidate();
            return;
        }

    }

    final Handler handler = new Handler() {
        @Override
        public void handleMessage(Message message) {
            BitmapWrapper wrapper = (BitmapWrapper)message.obj;
            if(wrapper.imageurl.equals(imageView.getTag().toString()))
            {
                imageView.setImageBitmap((Bitmap)wrapper.bitmap);
                imageView.invalidate();
            }

        }
    };

    Thread thread = new Thread() {
        @Override
        public void run() {
            //TODO : set imageView to a "pending" image

            Bitmap drawable = fetchDrawable(urlString);
            BitmapWrapper wrapper = new BitmapWrapper();
            wrapper.bitmap = drawable;
            wrapper.imageurl = urlString;
            Message message = handler.obtainMessage(1, wrapper);
            handler.sendMessage(message);
        }
    };
    thread.start();
}


    public class BitmapWrapper
{
    public Bitmap bitmap;
    public String imageurl;
}

J'ai eu le même problème.

Après presque 2 jours de gros débogage / optimisation et tentatives de résolution du problème, pourquoi mon getView () est appelé pour toutes les vues encore et encore lors de l'utilisation de setImageBitmap () in a Row, j’ai trouvé une solution sale:

1) Étendez un ImageView personnalisé que vous utiliserez pour toutes les images de votre liste

.

2) dans ce ImageView écrasez la méthode

@Override
public void requestLayout()
{ 
  return; 
}

3) Sale, mais pour moi ça marche

4) Bénéfice;)

J'ai un ThumbnailAdapter qui résume tout ce schéma susceptible de vous aider.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top