1898 votes

Comment dois-je faire un chargement différé des images dans ListView?

Je suis à l'aide d'un ListView d'afficher des images et des légendes associées à ces images. Je reçois les images à partir d'Internet. Est-il un moyen de chargement différé des images, de sorte que le texte s'affiche, l'INTERFACE utilisateur n'est pas verrouillé et les images sont affichées en tant qu'ils sont téléchargés?

Le nombre d'images n'est pas fixe.

1079voto

James A Wilson Points 7274

Voici ce que j'ai créé pour contenir les images que mon application est en cours d'affichage. Veuillez noter que le "Journal" de l'objet en cours d'utilisation, voici mon custom wrapper autour de la finale du Journal de classe à l'intérieur d'Android.

package com.wilson.android.library;

/*
 Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements.  See the NOTICE file
distributed with this work for additional information
regarding copyright ownership.  The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License.  You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied.  See the License for the
specific language governing permissions and limitations
under the License.
*/
import java.io.IOException;

public class DrawableManager {
    private final Map<String, Drawable> drawableMap;

    public DrawableManager() {
        drawableMap = new HashMap<String, Drawable>();
    }

    public Drawable fetchDrawable(String urlString) {
        if (drawableMap.containsKey(urlString)) {
            return drawableMap.get(urlString);
        }

        Log.d(this.getClass().getSimpleName(), "image url:" + urlString);
        try {
            InputStream is = fetch(urlString);
            Drawable drawable = Drawable.createFromStream(is, "src");


            if (drawable != null) {
                drawableMap.put(urlString, drawable);
                Log.d(this.getClass().getSimpleName(), "got a thumbnail drawable: " + drawable.getBounds() + ", "
                        + drawable.getIntrinsicHeight() + "," + drawable.getIntrinsicWidth() + ", "
                        + drawable.getMinimumHeight() + "," + drawable.getMinimumWidth());
            } else {
              Log.w(this.getClass().getSimpleName(), "could not get thumbnail");
            }

            return drawable;
        } catch (MalformedURLException e) {
            Log.e(this.getClass().getSimpleName(), "fetchDrawable failed", e);
            return null;
        } catch (IOException e) {
            Log.e(this.getClass().getSimpleName(), "fetchDrawable failed", e);
            return null;
        }
    }

    public void fetchDrawableOnThread(final String urlString, final ImageView imageView) {
        if (drawableMap.containsKey(urlString)) {
            imageView.setImageDrawable(drawableMap.get(urlString));
        }

        final Handler handler = new Handler() {
            @Override
            public void handleMessage(Message message) {
                imageView.setImageDrawable((Drawable) message.obj);
            }
        };

        Thread thread = new Thread() {
            @Override
            public void run() {
                //TODO : set imageView to a "pending" image
                Drawable drawable = fetchDrawable(urlString);
                Message message = handler.obtainMessage(1, drawable);
                handler.sendMessage(message);
            }
        };
        thread.start();
    }

    private InputStream fetch(String urlString) throws MalformedURLException, IOException {
        DefaultHttpClient httpClient = new DefaultHttpClient();
        HttpGet request = new HttpGet(urlString);
        HttpResponse response = httpClient.execute(request);
        return response.getEntity().getContent();
    }
}

1022voto

Fedor Points 29890

J'ai fait une simple démo d'un paresseux liste (situé sur GitHub), avec des images. Il peut être utile à quelqu'un. Il télécharge des images dans le thread d'arrière-plan. Les Images sont mises en cache sur une carte SD et de la mémoire. Le cache de la mise en œuvre est très simple et il est juste assez pour la démo. Je décoder les images avec inSampleSize à réduire la consommation de mémoire. J'ai aussi essayer de gérer recyclé vues correctement.

Alt text

550voto

NOSTRA Points 7459

Je recommande open source instrument Universel de Chargeur d'Image. Il est basé à l'origine sur Fedor Vlassov projet LazyList et a été grandement améliorée depuis.

  • Multithread chargement de l'image
  • Possibilité de l'échelle de syntonisation ImageLoader de configuration (thread exécuteurs testamentaires, downlaoder, décodeur, la mémoire et le cache sur disque, à l'image de l'écran des options, et autres)
  • Possibilité de l'image mise en cache en mémoire et/ou sur les fichiers de l'appareil sysytem (ou carte SD)
  • Possibilité "d'écouter" le processus de chargement
  • Possibilité de personnaliser chaque image de l'écran d'appel avec des options séparées
  • Widget de soutien
  • Android 2.0+ support

UniversalImageLoader.png

157voto

Thomas Ahle Points 10403

Le Multithreading Pour la Performance, un tutoriel par Gilles Debunne.

C'est à partir de l'Développeurs Android Blog. La suggestion de code utilise:

  • AsyncTasks.
  • Un dur, de taille limitée, FIFO cache.
  • Un doux, facilement garbage collect-ed cache.
  • Un espace réservé Drawable , pendant que vous téléchargez.

enter image description here

106voto

TalkLittle Points 2278

Mise à jour: Notez que cette réponse est assez inefficace maintenant. Le Garbage Collector agit de manière agressive sur SoftReference et WeakReference, de sorte que ce code n'est PAS adapté pour de nouvelles applications. (Au lieu de cela, essayez de bibliothèques comme Image Universelle de Chargeur suggéré dans d'autres réponses.)

Merci à James pour le code, et Bao Long de la suggestion de l'utilisation de SoftReference. J'ai mis en place le SoftReference changements sur James' code. Malheureusement SoftReferences causé mes images à ordures collectées trop rapidement. Dans mon cas, c'était très bien sans le SoftReference de trucs, parce que ma taille de la liste est limitée et mes images sont petites.

Il y a une discussion d'il y a un an au sujet de la SoftReferences sur google groupes: lien vers le fil. Comme une solution pour le trop-début de la collecte des ordures, ils suggèrent la possibilité de réglage manuel de la VM taille de segment de mémoire à l'aide de dalvik.système.VMRuntime.setMinimumHeapSize(), qui n'est pas très attrayant pour moi.

public DrawableManager() {
    drawableMap = new HashMap<String, SoftReference<Drawable>>();
}

public Drawable fetchDrawable(String urlString) {
    SoftReference<Drawable> drawableRef = drawableMap.get(urlString);
    if (drawableRef != null) {
        Drawable drawable = drawableRef.get();
        if (drawable != null)
            return drawable;
        // Reference has expired so remove the key from drawableMap
        drawableMap.remove(urlString);
    }

    if (Constants.LOGGING) Log.d(this.getClass().getSimpleName(), "image url:" + urlString);
    try {
        InputStream is = fetch(urlString);
        Drawable drawable = Drawable.createFromStream(is, "src");
        drawableRef = new SoftReference<Drawable>(drawable);
        drawableMap.put(urlString, drawableRef);
        if (Constants.LOGGING) Log.d(this.getClass().getSimpleName(), "got a thumbnail drawable: " + drawable.getBounds() + ", "
                + drawable.getIntrinsicHeight() + "," + drawable.getIntrinsicWidth() + ", "
                + drawable.getMinimumHeight() + "," + drawable.getMinimumWidth());
        return drawableRef.get();
    } catch (MalformedURLException e) {
        if (Constants.LOGGING) Log.e(this.getClass().getSimpleName(), "fetchDrawable failed", e);
        return null;
    } catch (IOException e) {
        if (Constants.LOGGING) Log.e(this.getClass().getSimpleName(), "fetchDrawable failed", e);
        return null;
    }
}

public void fetchDrawableOnThread(final String urlString, final ImageView imageView) {
    SoftReference<Drawable> drawableRef = drawableMap.get(urlString);
    if (drawableRef != null) {
        Drawable drawable = drawableRef.get();
        if (drawable != null) {
            imageView.setImageDrawable(drawableRef.get());
            return;
        }
        // Reference has expired so remove the key from drawableMap
        drawableMap.remove(urlString);
    }

    final Handler handler = new Handler() {
        @Override
        public void handleMessage(Message message) {
            imageView.setImageDrawable((Drawable) message.obj);
        }
    };

    Thread thread = new Thread() {
        @Override
        public void run() {
            //TODO : set imageView to a "pending" image
            Drawable drawable = fetchDrawable(urlString);
            Message message = handler.obtainMessage(1, drawable);
            handler.sendMessage(message);
        }
    };
    thread.start();
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X