So laden Sie Bilder in ListView in Android faul

1931

Ich verwende a ListView, um einige Bilder und Bildunterschriften anzuzeigen, die diesen Bildern zugeordnet sind. Ich bekomme die Bilder aus dem Internet. Gibt es eine Möglichkeit, Bilder verzögert zu laden, damit während der Text angezeigt wird, die Benutzeroberfläche nicht blockiert wird und Bilder beim Herunterladen angezeigt werden?

Die Gesamtzahl der Bilder ist nicht festgelegt.

lostInTransit
quelle
10
Sie können AsyncImageView von GreenDroid verwenden . Rufen Sie einfach an setUrl.
Pascal Dimassimo
7
Ich habe es benutzt. Es ist eine wunderbare Implementierung. Schlechte Nachrichten, dass AsyncImageView Teil eines großen GreenDroid-Projekts ist, wodurch Ihre Anwendung größer wird, selbst wenn Sie nur AsyncImageView benötigen. Außerdem scheint das GreenDroid-Projekt seit 2011 nicht mehr aktualisiert worden zu sein.
Borisstr
5
Sie können diese Bibliothek sogar ausprobieren: Android-http-image-manager, der meiner Meinung nach am besten zum asynchronen Laden von Bildern geeignet ist.
Ritesh Kumar Dubey
34
Verwenden Sie einfach Picasso, es wird alles von selbst tun. 'Picasso.with (yourContext) .load (img src / path / drawable here) .into (imageView dh Ihr Ziel);' Das ist es!
Anuj Sharma
6
Versuchen Sie es mit: github.com/nostra13/Android-Universal-Image-Loader , diese Bibliothek ist sehr schnell und effizient für
langsames

Antworten:

1087

Folgendes habe ich erstellt, um die Bilder aufzunehmen, die meine App derzeit anzeigt. Bitte beachten Sie, dass das hier verwendete "Log" -Objekt mein benutzerdefinierter Wrapper um die letzte Log-Klasse in Android ist.

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();
    }
}
James A Wilson
quelle
104
Ich denke, Sie sollten SoftReferences verwenden, damit Ihr Programm niemals OutOfMemoryException verursacht. Da GC Softreferenzen löschen kann, wenn die Größe des Heapspeichers zunimmt, können Sie Ihre eigene Generation verwalten. Nach einigen Sekunden können Sie Ihre Bilder in diese Liste aufnehmen. Vor dem Laden sollten Sie überprüfen, ob das Bild vorhanden ist, und es nicht erneut herunterladen, sondern sammeln es von dieser Liste und auch wieder auf Ihre Softref-Liste setzen und nach einiger Zeit können Sie Ihre Hardlist löschen :)
AZ_
36
Das Google Shelves-Projekt ist ein hervorragendes Beispiel dafür, wie sie code.google.com/p/shelves
AZ_ am
12
Verpassen Sie keine Rückgabe, wenn drawableMap das Bild enthält ... ohne den Abruf-Thread zu starten?
Karussell
5
Dieser Code hat mehrere Probleme. Zunächst sollten Sie Drawables zwischenspeichern, da dies zu einem Speicherverlust führt: stackoverflow.com/questions/7648740/… . Zweitens wird der Cache selbst nie geleert, sodass er für immer wächst. Dies ist ein weiterer Speicherverlust.
Samstag, 19.
10
Ich habe noch nichts von LRU Cache developer.android.com/training/displaying-bitmaps/ gehört.
Muhammad Babar
1025

Ich habe eine einfache Demo einer faulen Liste (bei GitHub) mit Bildern erstellt.

Grundlegende Verwendung

ImageLoader imageLoader=new ImageLoader(context); ...
imageLoader.DisplayImage(url, imageView); 

Vergessen Sie nicht, Ihrer AndroidManifest.xml die folgenden Berechtigungen hinzuzufügen:

 <uses-permission android:name="android.permission.INTERNET"/>
 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> Please

Erstellen Sie nur eine Instanz von ImageLoader und verwenden Sie sie rund um Ihre Anwendung wieder. Auf diese Weise wird das Zwischenspeichern von Bildern wesentlich effizienter.

Es kann für jemanden hilfreich sein. Es werden Bilder im Hintergrund-Thread heruntergeladen. Bilder werden auf einer SD-Karte und im Speicher zwischengespeichert. Die Cache-Implementierung ist sehr einfach und reicht gerade für die Demo aus. Ich dekodiere Bilder mit inSampleSize, um den Speicherverbrauch zu reduzieren. Ich versuche auch, mit recycelten Ansichten richtig umzugehen.

Alt-Text

Fedor
quelle
7
Vielen Dank, ich verwende fast überall in meinem Projekt eine leicht modifizierte Version Ihres Codes: code.google.com/p/vimeoid/source/browse/apk/src/com/fedorvlasov/…
shaman.sir
3
Hat sich jemand den Code von Gilles Debunne als Alternative angesehen? Die zwei großen Unterschiede, die ich sehe, sind 1) beim Zwischenspeichern des Speichers gegenüber der SD-Karte und 2) die Verwendung von AsyncTasks anstelle eines Thread-Pools. android-developers.blogspot.com/2010/07/…
Richard
4
Es gibt einen Fehler, manchmal wird er ausgelöst: 10-13 09: 58: 46.738: ERROR / AndroidRuntime (24250): Nicht erfasster Handler: Thread-Haupt wird aufgrund einer nicht erfassten Ausnahme beendet 10-13 09: 58: 46.768: ERROR / AndroidRuntime (24250) : java.lang.ArrayIndexOutOfBoundsException: Array-Index außerhalb des Bereichs: 0 10-13 09: 58: 46.768: ERROR / AndroidRuntime (24250): at java.util.Vector.elementAt (Vector.java:331) 10-13 09: 58: 46.768: ERROR / AndroidRuntime (24250): at java.util.Vector.get (Vector.java:445) 10-13 09: 58: 46.768: ERROR / AndroidRuntime (24250): at com.my.app.image .ImageLoader $ PhotosQueue.Clean (ImageLoader.java:91)
Mikooos
64
Ich möchte für Neulinge wie mich hinzufügen, dass Sie, wenn Sie diesen Code zu Ihrem eigenen Projekt hinzufügen möchten, externe Cache-Berechtigungen im Manifest hinzufügen müssen. Vielen Dank
Adam
2
@BruceHill Der neueste Quellcode enthält keine photosQueue. Sie scheinen eine sehr alte Version zu verwenden.
Fedor
552

Ich empfehle das Open Source Instrument Universal Image Loader . Es basiert ursprünglich auf Fedor Vlasovs Projekt LazyList und wurde seitdem erheblich verbessert.

  • Laden von Multithread-Bildern
  • Möglichkeit der umfassenden Optimierung der ImageLoader-Konfiguration (Thread-Executoren, Downlaoder, Decoder, Speicher- und Disc-Cache, Anzeige von Bildoptionen und andere)
  • Möglichkeit der Bildspeicherung im Speicher und / oder auf dem Dateisystem des Geräts (oder der SD-Karte)
  • Möglichkeit zum "Abhören" des Ladevorgangs
  • Möglichkeit, jeden Anzeigebildaufruf mit getrennten Optionen anzupassen
  • Widget-Unterstützung
  • Android 2.0+ Unterstützung

nostra13
quelle
16
Wenn Sie nach großartigem Code zum Laden von Bildern suchen, den der Ersteller als sein kostbares Baby behandelt und pflegt (nicht nur eine einmalige Lösung), haben Sie ihn gerade gefunden. Big Ups Nostra
AndroidGecko
Wirklich großartige Arbeit, aber sie bleibt ein bisschen hinter meiner Listenansicht zurück. Wenn Sie die beste Leistung für den 'ImageLoader'-Build feststellen könnten ... oder vielleicht wegen der' DisplayImageOptions '.
Dinigo
Ich liebe diese Rasteransicht so sehr, aber ich kann sie nicht für mein Tutorial verwenden. Ich bin ein Anfänger von Android. Ich mache eine Anwendung über Gridview, aber meine Anwendung war targetSdkVersion 15, daher muss ich Asynctask für den Prozess im Hintergrundthread verwenden. Ich habe diese Rasteransicht verwendet, aber sie funktioniert nicht. Wie kann ich es in targetSdkVersion 15 verwenden?
Kongkea
Sie können eine separate Frage mit dem Tag [Universal-Image-Loader]
erstellen
3
Nachdem ich die offiziellen Android-Dokumente gelesen und versucht habe, dieses Zeug selbst zu machen, bin ich mir ziemlich sicher, dass diese Bibliothek das Ende des gesamten Bildladens ist. Kann nicht genug stimmen.
Core
159

Multithreading For Performance , ein Tutorial von Gilles Debunne.

Dies ist aus dem Android Developers Blog. Der vorgeschlagene Code verwendet:

  • AsyncTasks.
  • Eine harte, begrenzte Größe FIFO cache.
  • Ein weicher, leicht zu garbage collecthandhabender Cache.
  • Ein Platzhalter Drawable beim Herunterladen.

Geben Sie hier die Bildbeschreibung ein

Thomas Ahle
quelle
10
Es funktioniert auch in 2.1 gut. Verwenden Sie einfach nicht AndroidHttpClient.
Thomas Ahle
2
@ thomas-ahle Danke, ich habe gesehen, dass AndroidHttpClient Fehler in 2.1 gab, da es ab 2.2 implementiert wurde, aber nicht wirklich versucht hat, etwas anderes zu finden, um es zu ersetzen.
Adinia
4
@Adina Du hast recht, ich habe es vergessen. Das Rezept enthält jedoch nichts, was mit einem normalen HttpClient nicht so gut gemacht werden kann.
Thomas Ahle
Ich habe an mehreren Stellen gehört, dass Google keine weichen Referenzen empfiehlt, da der Android-Kernel diese Referenzen im Vergleich zu früheren Versionen des Systems sehr gerne sammelt.
Muhammad Ahmed Abu Talib
109

Update: Beachten Sie, dass diese Antwort jetzt ziemlich unwirksam ist. Der Garbage Collector reagiert aggressiv auf SoftReference und WeakReference, sodass dieser Code NICHT für neue Apps geeignet ist. (Versuchen Sie stattdessen Bibliotheken wie Universal Image Loader , die in anderen Antworten vorgeschlagen wurden.)

Vielen Dank an James für den Code und Bao-Long für den Vorschlag, SoftReference zu verwenden. Ich habe die SoftReference-Änderungen in James 'Code implementiert. Leider haben SoftReferences dazu geführt, dass meine Bilder zu schnell im Müll gesammelt wurden. In meinem Fall war es ohne das SoftReference-Zeug in Ordnung, da meine Listengröße begrenzt und meine Bilder klein sind.

Es gibt eine Diskussion vor einem Jahr über die SoftReferences in Google-Gruppen: Link zum Thread . Als Lösung für die zu frühe Speicherbereinigung schlagen sie die Möglichkeit vor, die VM-Heap-Größe manuell mit dalvik.system.VMRuntime.setMinimumHeapSize () festzulegen, was für mich nicht sehr attraktiv ist.

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();
}
TalkLittle
quelle
3
Sie können Generationen wie Hard-Generation und Soft-Generation erstellen. Sie können einen Zeit-Clear-Cache reparieren, der alle Bilder
löscht
developer.android.com/reference/java/lang/ref/… Das SoftReference-Dokument enthält einen Hinweis zum Caching, siehe Abschnitt "Vermeiden von Softreferenzen für das Caching". Die meisten Anwendungen sollten einen android.util.LruCache anstelle von weichen Referenzen verwenden.
Vokilam
Ich bewundere Ihren Code, aber jetzt gibt es im neuen Android-Betriebssystem "aggressive" Müllabfuhr. Eine schwache Referenz zu halten, macht für mich keinen Sinn.
j2emanue
@ j2emanue Sie haben Recht, wie ich oben in meiner Antwort angegeben habe, sind SoftReferences zu schnell gesammelter Müll. Ich werde versuchen, diese Antwort zu bearbeiten, um das noch klarer zu machen.
TalkLittle
97

Picasso

Verwenden Sie die Picasso-Bibliothek von Jake Wharton. (Eine perfekte ImageLoading-Bibliothek vom Entwickler von ActionBarSherlock)

Eine leistungsstarke Bibliothek zum Herunterladen und Zwischenspeichern von Bildern für Android.

Bilder verleihen Android-Anwendungen den dringend benötigten Kontext und das visuelle Flair. Picasso ermöglicht das problemlose Laden von Bildern in Ihre Anwendung - häufig in einer Codezeile!

Picasso.with(context).load("http://i.imgur.com/DvpvklR.png").into(imageView);

Viele häufige Probleme beim Laden von Bildern unter Android werden von Picasso automatisch behoben:

Umgang mit ImageView-Recycling und Download-Stornierung in einem Adapter. Komplexe Bildtransformationen mit minimalem Speicherbedarf. Automatisches Zwischenspeichern von Speicher und Festplatten.

Picasso Jake Whartons Bibliothek

Gleiten

Glide ist ein schnelles und effizientes Open Source-Medienverwaltungsframework für Android, das Mediendecodierung, Speicher- und Festplatten-Caching sowie Ressourcenpooling in einer einfachen und benutzerfreundlichen Oberfläche zusammenfasst.

Glide unterstützt das Abrufen, Dekodieren und Anzeigen von Videostills, Bildern und animierten GIFs. Glide enthält eine flexible API, mit der Entwickler fast jeden Netzwerkstapel anschließen können. Standardmäßig verwendet Glide einen benutzerdefinierten HttpUrlConnection-basierten Stack, enthält jedoch auch Dienstprogrammbibliotheken, die in das Volley-Projekt von Google oder in die OkHttp-Bibliothek von Square eingebunden sind.

Glide.with(this).load("http://goo.gl/h8qOq7").into(imageView);

Der Hauptfokus von Glide liegt darauf, das Scrollen einer Liste von Bildern so reibungslos und schnell wie möglich zu gestalten. Glide ist jedoch auch in fast allen Fällen wirksam, in denen Sie ein Remote-Bild abrufen, seine Größe ändern und anzeigen müssen.

Glide Image Loading Library

Fresko von Facebook

Fresco ist ein leistungsstarkes System zur Anzeige von Bildern in Android-Anwendungen.

Fresco kümmert sich um das Laden und Anzeigen von Bildern, sodass Sie dies nicht tun müssen. Es werden Bilder aus dem Netzwerk, dem lokalen Speicher oder lokalen Ressourcen geladen und ein Platzhalter angezeigt, bis das Bild angekommen ist. Es hat zwei Cache-Ebenen; eine im Speicher und eine im internen Speicher.

Fresko Github

In Android 4.x und niedriger legt Fresco Bilder in einem speziellen Bereich des Android-Speichers ab. Dadurch kann Ihre Anwendung schneller ausgeführt werden - und der gefürchtete OutOfMemoryError tritt viel seltener auf.

Fresko-Dokumentation

Ashwin S Ashok
quelle
Picasso ist eine Bibliothek, die von Square
LordRaydenMK
83

Hochleistungslader - nachdem ich die hier vorgeschlagenen Methoden untersucht hatte, verwendete ich Bens Lösung mit einigen Änderungen -

  1. Ich habe festgestellt, dass die Arbeit mit Drawables schneller ist als mit Bitmaps, daher verwende ich stattdessen Drawables

  2. Die Verwendung von SoftReference ist großartig, führt jedoch dazu, dass das zwischengespeicherte Bild zu oft gelöscht wird. Daher habe ich eine verknüpfte Liste hinzugefügt, die Bildreferenzen enthält, um zu verhindern, dass das Bild gelöscht wird, bis es eine vordefinierte Größe erreicht hat

  3. Um den InputStream zu öffnen, habe ich java.net.URLConnection verwendet, mit dem ich den Webcache verwenden kann (Sie müssen zuerst einen Antwortcache festlegen, aber das ist eine andere Geschichte).

Mein Code:

import java.util.Map; 
import java.util.HashMap; 
import java.util.LinkedList; 
import java.util.Collections; 
import java.util.WeakHashMap; 
import java.lang.ref.SoftReference; 
import java.util.concurrent.Executors; 
import java.util.concurrent.ExecutorService; 
import android.graphics.drawable.Drawable;
import android.widget.ImageView;
import android.os.Handler;
import android.os.Message;
import java.io.InputStream;
import java.net.MalformedURLException; 
import java.io.IOException; 
import java.net.URL;
import java.net.URLConnection;

public class DrawableBackgroundDownloader {    

private final Map<String, SoftReference<Drawable>> mCache = new HashMap<String, SoftReference<Drawable>>();   
private final LinkedList <Drawable> mChacheController = new LinkedList <Drawable> ();
private ExecutorService mThreadPool;  
private final Map<ImageView, String> mImageViews = Collections.synchronizedMap(new WeakHashMap<ImageView, String>());  

public static int MAX_CACHE_SIZE = 80; 
public int THREAD_POOL_SIZE = 3;

/**
 * Constructor
 */
public DrawableBackgroundDownloader() {  
    mThreadPool = Executors.newFixedThreadPool(THREAD_POOL_SIZE);  
}  


/**
 * Clears all instance data and stops running threads
 */
public void Reset() {
    ExecutorService oldThreadPool = mThreadPool;
    mThreadPool = Executors.newFixedThreadPool(THREAD_POOL_SIZE);
    oldThreadPool.shutdownNow();

    mChacheController.clear();
    mCache.clear();
    mImageViews.clear();
}  

public void loadDrawable(final String url, final ImageView imageView,Drawable placeholder) {  
    mImageViews.put(imageView, url);  
    Drawable drawable = getDrawableFromCache(url);  

    // check in UI thread, so no concurrency issues  
    if (drawable != null) {  
        //Log.d(null, "Item loaded from mCache: " + url);  
        imageView.setImageDrawable(drawable);  
    } else {  
        imageView.setImageDrawable(placeholder);  
        queueJob(url, imageView, placeholder);  
    }  
} 


private Drawable getDrawableFromCache(String url) {  
    if (mCache.containsKey(url)) {  
        return mCache.get(url).get();  
    }  

    return null;  
}

private synchronized void putDrawableInCache(String url,Drawable drawable) {  
    int chacheControllerSize = mChacheController.size();
    if (chacheControllerSize > MAX_CACHE_SIZE) 
        mChacheController.subList(0, MAX_CACHE_SIZE/2).clear();

    mChacheController.addLast(drawable);
    mCache.put(url, new SoftReference<Drawable>(drawable));

}  

private void queueJob(final String url, final ImageView imageView,final Drawable placeholder) {  
    /* Create handler in UI thread. */  
    final Handler handler = new Handler() {  
        @Override  
        public void handleMessage(Message msg) {  
            String tag = mImageViews.get(imageView);  
            if (tag != null && tag.equals(url)) {
                if (imageView.isShown())
                    if (msg.obj != null) {
                        imageView.setImageDrawable((Drawable) msg.obj);  
                    } else {  
                        imageView.setImageDrawable(placeholder);  
                        //Log.d(null, "fail " + url);  
                    } 
            }  
        }  
    };  

    mThreadPool.submit(new Runnable() {  
        @Override  
        public void run() {  
            final Drawable bmp = downloadDrawable(url);
            // if the view is not visible anymore, the image will be ready for next time in cache
            if (imageView.isShown())
            {
                Message message = Message.obtain();  
                message.obj = bmp;
                //Log.d(null, "Item downloaded: " + url);  

                handler.sendMessage(message);
            }
        }  
    });  
}  



private Drawable downloadDrawable(String url) {  
    try {  
        InputStream is = getInputStream(url);

        Drawable drawable = Drawable.createFromStream(is, url);
        putDrawableInCache(url,drawable);  
        return drawable;  

    } catch (MalformedURLException e) {  
        e.printStackTrace();  
    } catch (IOException e) {  
        e.printStackTrace();  
    }  

    return null;  
}  


private InputStream getInputStream(String urlString) throws MalformedURLException, IOException {
    URL url = new URL(urlString);
    URLConnection connection;
    connection = url.openConnection();
    connection.setUseCaches(true); 
    connection.connect();
    InputStream response = connection.getInputStream();

    return response;
}
}
Pinhassi
quelle
Funktioniert super! Übrigens enthält der Klassenname einen Tippfehler.
Mullins
5
Für den Fall, dass es jemand anderem die Zeit spart: import java.util.Map; import java.util.HashMap; import java.util.LinkedList; import java.util.Collections; import java.util.WeakHashMap; import java.lang.ref.SoftReference; import java.util.concurrent.Executors; import java.util.concurrent.ExecutorService; import android.graphics.drawable.Drawable; import android.widget.ImageView; import android.os.Handler; import android.os.Message; import java.io.InputStream; import java.net.MalformedURLException; import java.io.IOException; import java.net.URL; import java.net.URLConnection;
Michael Reed
Vielen Dank, dies ist eine schöne Implementierung. Ich habe auch einen anderen Platzhalter für das Laden des Drawables eingefügt, damit der Benutzer Feedback erhalten kann.
Juan Hernandez
Ich denke auch, dass es besser ist, eine LIFO-Warteschlange im executorService (mThreadPool) anstelle des Standard-FIFO zu verwenden, damit die zuletzt angeforderten Bilder (die wahrscheinlich die sichtbaren sind) zuerst geladen werden. Siehe stackoverflow.com/questions/4620061/how-to-create-lifo-executor
Juan Hernandez
9
@MichaelReed, falls Sie ein Eclipse-Benutzer sind, empfehle ich die Verwendung von Strg-Umschalt-O (das ist der Buchstabe O, nicht die Zahl 0). Es automatisiert das Hinzufügen von Importen und organisiert diese für Sie. Wenn Sie einen Mac verwenden, verwenden Sie stattdessen Command-Shift-O.
SilithCrowe
78

Ich habe dieses Android-Training absolviert und denke, dass es beim Herunterladen von Bildern hervorragende Arbeit leistet, ohne die Hauptbenutzeroberfläche zu blockieren. Es behandelt auch das Zwischenspeichern und das Scrollen durch viele Bilder: Effizientes Laden großer Bitmaps

toobsco42
quelle
Es tut mir leid, ich habe nur auf eine einzelne Klasse für die Google IO-App hingewiesen (und ich bin zu spät zum Bearbeiten). Sie sollten wirklich alle Dienstprogrammklassen zum Laden und Zwischenspeichern von Bildern studieren, die Sie im selben Paket wie die Cache-Klasse finden .
mkuech
Würde jemand empfehlen, die DiskLruCache-, Image * .java-Dateien aus dem util-Ordner der iosched-App abzurufen, um das Laden / Zwischenspeichern von Bildern für die Listenansicht zu erleichtern? Ich meine, es lohnt sich auf jeden Fall, den Online-Entwicklerhandbüchern zu diesem Thema zu folgen, aber diese Klassen (von iosched) gehen mit dem Muster etwas weiter.
Gautam
65

1. Picasso ermöglicht das problemlose Laden von Bildern in Ihre Anwendung - häufig in einer Codezeile!

Verwenden Sie Gradle:

implementation 'com.squareup.picasso:picasso:2.71828'

Nur eine Codezeile!

Picasso.get().load("http://i.imgur.com/DvpvklR.png").into(imageView);

2. Glide Eine Bibliothek zum Laden und Zwischenspeichern von Bildern für Android, die sich auf reibungsloses Scrollen konzentriert

Verwenden Sie Gradle:

repositories {
  mavenCentral() 
  google()
}

dependencies {
   implementation 'com.github.bumptech.glide:glide:4.7.1'
   annotationProcessor 'com.github.bumptech.glide:compiler:4.7.1'
}

// Für eine einfache Ansicht:

  Glide.with(this).load("http://i.imgur.com/DvpvklR.png").into(imageView);

3. fresco ist ein leistungsstarkes System zum Anzeigen von Bildern in Android-Anwendungen . Fresco kümmert sich um das Laden und Anzeigen von Bildern, sodass Sie dies nicht tun müssen.

Erste Schritte mit Fresco

Chiragkyada
quelle
Dieses Tutorial kann Ihnen mehr für PICASOO helfen: - androidtutorialshub.com/… und GLIDE: - androidtutorialshub.com/…
lalit vasan
52

Ich habe ein Tutorial geschrieben, in dem erklärt wird, wie Bilder in einer Listenansicht verzögert geladen werden. Ich gehe auf die Themen Recycling und Parallelität ein. Ich verwende auch einen festen Thread-Pool, um zu verhindern, dass viele Threads entstehen.

Faules Laden von Bildern im Listview Tutorial

Ben Ruijl
quelle
41

Ich starte dazu einen Thread, um die Bilder im Hintergrund herunterzuladen und ihm für jedes Listenelement einen Rückruf zu geben. Wenn ein Bild vollständig heruntergeladen wurde, wird der Rückruf aufgerufen, der die Ansicht für das Listenelement aktualisiert.

Diese Methode funktioniert jedoch nicht sehr gut, wenn Sie Ansichten recyceln.

Jasonhudgins
quelle
Die Verwendung eines Threads für jedes Bild ist der Ansatz, den ich ebenfalls verwende. Wenn Sie Ihr Modell von Ihrer Ansicht trennen, können Sie das Modell außerhalb der Aktivität beibehalten (wie in Ihrer Anwendungsklasse), um es zwischengespeichert zu halten. Achten Sie darauf, dass Ihnen nicht die Ressourcen ausgehen, wenn Sie viele Bilder haben.
James A Wilson
Können Sie bitte näher darauf eingehen? Ich bin neu in der Android-Entwicklung. Vielen Dank für die Tipps
lostInTransit
14
Das Starten eines neuen Threads für jedes Bild ist keine effektive Lösung. Sie können mit vielen Threads im Speicher enden und die Benutzeroberfläche einfrieren.
Fedor
Fedor, stimmte zu, ich benutze normalerweise eine Warteschlange und einen Thread-Pool, das ist der beste Weg, um imo zu gehen.
Jasonhudgins
32

Ich möchte nur noch ein gutes Beispiel hinzufügen, XML-Adapter . Da es von Google verwendet wird und ich auch die gleiche Logik verwende, um einen OutOfMemory-Fehler zu vermeiden.

Grundsätzlich ist dieser ImageDownloader Ihre Antwort (da er die meisten Ihrer Anforderungen abdeckt). Einige können Sie auch darin implementieren.

Arslan Anwar
quelle
2
ImageDownloader-Klasse wird nicht erfüllt: siehe die Lösung unten code.google.com/p/parleys-android-nextgen/issues/detail?id=1
Sam
29

Dies ist ein häufiges Problem unter Android, das von vielen Menschen auf viele Arten gelöst wurde. Meiner Meinung nach ist die beste Lösung, die ich gesehen habe, die relativ neue Bibliothek namens Picasso . Hier sind die Highlights:

  • Open Source, sondern geleitet Jake Whartonvon ActionBarSherlock Ruhm.
  • Laden Sie Bilder aus Netzwerk- oder App-Ressourcen asynchron mit einer Codezeile
  • Automatische ListViewErkennung
  • Automatisches Zwischenspeichern von Festplatten und Speicher
  • Kann benutzerdefinierte Transformationen durchführen
  • Viele konfigurierbare Optionen
  • Super einfache API
  • Häufig aktualisiert
howettl
quelle
29

Ich habe NetworkImageView aus der neuen Android Volley Library verwendet com.android.volley.toolbox.NetworkImageViewund es scheint ziemlich gut zu funktionieren. Anscheinend ist dies dieselbe Ansicht, die in Google Play und anderen neuen Google-Anwendungen verwendet wird. Auf jeden Fall einen Besuch wert.

Droidment
quelle
1
Ich denke, dies ist die beste Lösung - die anderen Antworten sind sehr alt - Volley ist wirklich schnell und in Kombination mit Jake Walshs Disklrucache eine perfekte Lösung - ich habe viele andere ausprobiert, aber keiner ist stabil und schnell wie Volley
Alexander Sidikov Pfeif
26

Die Ladezeit von Bildern aus dem Internet bietet viele Lösungen. Sie können auch die Bibliothek Android-Query verwenden . Es gibt Ihnen alle erforderlichen Aktivitäten. Stellen Sie sicher, was Sie tun möchten, und lesen Sie die Wiki-Seite der Bibliothek. Und lösen Sie die Einschränkung beim Laden von Bildern.

Das ist mein Code:

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    View v = convertView;
    if (v == null) {
        LayoutInflater vi = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        v = vi.inflate(R.layout.row, null);
    }

    ImageView imageview = (ImageView) v.findViewById(R.id.icon);
    AQuery aq = new AQuery(convertView);

    String imageUrl = "http://www.vikispot.com/z/images/vikispot/android-w.png";

    aq.id(imageview).progress(this).image(imageUrl, true, true, 0, 0, new BitmapAjaxCallback() {
        @Override
        public void callback(String url, ImageView iv, Bitmap bm, AjaxStatus status) {
            iv.setImageBitmap(bm);
        }
    ));

    return v;
}

Es sollte Ihr Problem beim verzögerten Laden lösen.

Rahul Rawat
quelle
Gute Arbeit für mich, aber Sie brauchen eine Jar-Datei, die Sie in Ihr Projekt aufnehmen können. Sie können diese JAR-Datei hier herunterladen. AQuery androidAQuery = new AQuery (this); Link ist: code.google.com/archive/p/android-query/downloads
Selim Raza
25

Ich denke, dieses Problem ist bei Android-Entwicklern sehr beliebt, und es gibt viele solcher Bibliotheken, die behaupten, dieses Problem zu beheben, aber nur wenige von ihnen scheinen auf dem richtigen Weg zu sein. AQuery ist eine solche Bibliothek, aber sie ist in allen Aspekten besser als die meisten anderen und es lohnt sich, sie auszuprobieren .

Ritesh Kumar Dubey
quelle
22

Sie müssen versuchen, dieser Universal Loader ist am besten. Ich benutze dies, nachdem ich viele RnD auf faulem Laden gemacht habe.

Universal Image Loader

Eigenschaften

  • Laden von Multithread-Bildern (asynchron oder synchron)
  • Umfassende Anpassung der ImageLoader-Konfiguration (Thread-Executoren, Downloader, Decoder, Speicher- und Festplatten-Cache, Anzeige von Image-Optionen usw.)
  • Viele Anpassungsoptionen für jeden Aufruf von Anzeigebildern (Stub-Bilder, Caching-Schalter, Decodierungsoptionen, Bitmap-Verarbeitung und -Anzeige usw.)
  • Bild-Caching im Speicher und / oder auf der Festplatte (Dateisystem oder SD-Karte des Geräts)
  • Ladevorgang beim Hören (einschließlich des Fortschritts beim Herunterladen)

Android 2.0+ Unterstützung

Geben Sie hier die Bildbeschreibung ein

Girish Patel
quelle
20

Schauen Sie sich Shutterbug an , Applidiums leichtgewichtigen SDWebImage-Port (eine schöne Bibliothek für iOS) für Android. Es unterstützt asynchrones Caching, speichert fehlgeschlagene URLs, behandelt Parallelität gut und hilfreiche Unterklassen sind enthalten.

Pull-Anfragen (und Fehlerberichte) sind ebenfalls willkommen!

PatrickNLT
quelle
16

DroidParts verfügt über ImageFetcher , für dessen Start keine Konfiguration erforderlich ist.

  • Verwendet einen LRU-Cache ( Least Recent Used ).
  • Dekodiert Bilder effizient.
  • Unterstützt das Ändern von Bitmaps im Hintergrundthread.
  • Hat einfache Überblendung.
  • Hat einen Rückruf zum Laden des Bildes.

Clone DroidPartsGram für ein Beispiel:

Geben Sie hier die Bildbeschreibung ein

yanchenko
quelle
Hallo, ich habe mir die Codebeispiele angesehen, aber ich habe Probleme bei der Verwendung von ImageFetcher mit einem ArrayAdapter. Würde es Ihnen etwas ausmachen, meine Frage zu betrachten? stackoverflow.com/questions/21089147/… Danke =]
Mascha
16

Nur ein kurzer Tipp für jemanden, der sich nicht sicher ist, welche Bibliothek zum verzögerten Laden von Bildern verwendet werden soll:

Es gibt vier grundlegende Möglichkeiten.

  1. DIY => Nicht die beste Lösung, aber für ein paar Bilder und wenn Sie auf den Aufwand verzichten möchten, andere Bibliotheken zu verwenden

  2. Volley's Lazy Loading Bibliothek => Von Jungs bei Android. Es ist schön und alles aber schlecht dokumentiert und daher ein Problem zu bedienen.

  3. Picasso: Eine einfache Lösung, die einfach funktioniert. Sie können sogar die genaue Bildgröße angeben, die Sie einbringen möchten. Sie ist sehr einfach zu verwenden, aber möglicherweise nicht sehr "performant" für Apps, die mit riesigen Bildmengen umgehen müssen.

  4. UIL: Der beste Weg, um Bilder faul zu laden. Sie können Bilder zwischenspeichern (Sie benötigen natürlich eine Erlaubnis), den Loader einmal initialisieren und dann Ihre Arbeit erledigen. Die ausgereifteste asynchrone Bildladebibliothek, die ich bisher gesehen habe.

Bijay Koirala
quelle
15

Novoda hat auch eine großartige Bibliothek zum Laden fauler Bilder und viele Apps wie Songkick, Podio, SecretDJ und ImageSearch verwenden ihre Bibliothek.

Ihre Bibliothek wird hier auf Github gehostet und sie haben auch einen ziemlich aktiven Issues Tracker . Ihr Projekt scheint auch ziemlich aktiv zu sein, mit über 300 Commits zum Zeitpunkt des Schreibens dieser Antwort.

Soham
quelle
1
Eigentlich ist Novoda eine großartige Bibliothek, aber ... manchmal braucht man keine große Bibliothek und nur einen einfachen Lösungsansatz. Deshalb ist LazyList in Github so gut, wenn Ihre Apps nur ein Bild in einer Listenansicht anzeigen und nicht das Hauptmerkmal Ihrer App sind, sondern nur eine andere Aktivität, die ich lieber mit etwas Leichterem verwenden würde. Andernfalls versuchen Sie Novoda, wenn Sie wissen, dass Sie häufig verwenden müssen und Teil des Kerns sind.
Nicolas Jafelle
13

Überprüfen Sie meine Gabelung von LazyList . Grundsätzlich verbessere ich die LazyList, indem ich den Aufruf der ImageView verzögere und zwei Methoden erstelle:

  1. Wenn Sie etwas wie "Bild laden ..." einfügen müssen
  2. Wenn Sie das heruntergeladene Bild anzeigen müssen.

Ich habe auch den ImageLoader verbessert, indem ich einen Singleton in dieses Objekt implementiert habe .

Nicolas Jafelle
quelle
12

Wenn Sie das Shimmer-Layout wie Facebook anzeigen möchten, gibt es dafür eine offizielle Facebook-Bibliothek. FaceBook Shimmer Android

Es kümmert sich um alles. Sie müssen nur Ihren gewünschten Design-Code verschachtelt in einen schimmernden Rahmen einfügen. Hier ist ein Beispielcode.

<com.facebook.shimmer.ShimmerFrameLayout
     android:id=“@+id/shimmer_view_container”
     android:layout_width=“wrap_content”
     android:layout_height="wrap_content"
     shimmer:duration="1000">

 <here will be your content to display />

</com.facebook.shimmer.ShimmerFrameLayout>

Und hier ist der Java-Code dafür.

ShimmerFrameLayout shimmerContainer = (ShimmerFrameLayout) findViewById(R.id.shimmer_view_container);
shimmerContainer.startShimmerAnimation();

Fügen Sie diese Abhängigkeit in Ihre Gradle-Datei ein.

implementation 'com.facebook.shimmer:shimmer:0.1.0@aar'

So sieht es aus.Schimmernder Android-Screenshot

Zankrut Parmar
quelle
11

Alle oben genannten Codes haben ihren eigenen Wert, aber mit meiner persönlichen Erfahrung versuchen Sie es einfach mit Picasso.

Picasso ist eine Bibliothek speziell für diesen Zweck. Tatsächlich verwaltet sie den Cache und alle anderen Netzwerkvorgänge automatisch. Sie müssen Ihrem Projekt eine Bibliothek hinzufügen und nur eine einzige Codezeile schreiben, um das Bild von der Remote-URL zu laden.

Bitte besuchen Sie hier: http://code.tutsplus.com/tutorials/android-sdk-working-with-picasso--cms-22149

AKber
quelle
9

Verwenden Sie die Gleitbibliothek. Es hat bei mir funktioniert und funktioniert auch bei Ihrem Code. Es funktioniert sowohl für Bilder als auch für Gifs.

ImageView imageView = (ImageView) findViewById(R.id.test_image); 
    GlideDrawableImageViewTarget imagePreview = new GlideDrawableImageViewTarget(imageView);
    Glide
            .with(this)
            .load(url)
            .listener(new RequestListener<String, GlideDrawable>() {
                @Override
                public boolean onException(Exception e, String model, Target<GlideDrawable> target, boolean isFirstResource) {                       
                    return false;
                }

                @Override
                public boolean onResourceReady(GlideDrawable resource, String model, Target<GlideDrawable> target, boolean isFromMemoryCache, boolean isFirstResource) {
                    return false;
                }
            })
            .into(imagePreview);
}
Saket Kumar
quelle
7

Ich kann einen anderen Weg empfehlen, der wie ein Zauber funktioniert: Android Query.

Sie können diese JAR- Datei hier herunterladen

AQuery androidAQuery = new AQuery(this);

Als Beispiel:

androidAQuery.id(YOUR IMAGEVIEW).image(YOUR IMAGE TO LOAD, true, true, getDeviceWidth(), ANY DEFAULT IMAGE YOU WANT TO SHOW);

Es ist sehr schnell und genau, und mit dieser Funktion finden Sie viele weitere Funktionen wie Animationen beim Laden, Abrufen einer Bitmap (falls erforderlich) usw.

Pratik Dasa
quelle
7

Probieren Sie Aquery aus . Es verfügt über erstaunlich einfache Methoden zum asynchronen Laden und Zwischenspeichern von Bildern.

user2779311
quelle
4
public class ImageDownloader {

Map<String, Bitmap> imageCache;

public ImageDownloader() {
    imageCache = new HashMap<String, Bitmap>();

}

// download function
public void download(String url, ImageView imageView) {
    if (cancelPotentialDownload(url, imageView)) {

        // Caching code right here
        String filename = String.valueOf(url.hashCode());
        File f = new File(getCacheDirectory(imageView.getContext()),
                filename);

        // Is the bitmap in our memory cache?
        Bitmap bitmap = null;

        bitmap = (Bitmap) imageCache.get(f.getPath());

        if (bitmap == null) {

            bitmap = BitmapFactory.decodeFile(f.getPath());

            if (bitmap != null) {
                imageCache.put(f.getPath(), bitmap);
            }

        }
        // No? download it
        if (bitmap == null) {
            try {
                BitmapDownloaderTask task = new BitmapDownloaderTask(
                        imageView);
                DownloadedDrawable downloadedDrawable = new DownloadedDrawable(
                        task);
                imageView.setImageDrawable(downloadedDrawable);
                task.execute(url);
            } catch (Exception e) {
                Log.e("Error==>", e.toString());
            }

        } else {
            // Yes? set the image
            imageView.setImageBitmap(bitmap);
        }
    }
}

// cancel a download (internal only)
private static boolean cancelPotentialDownload(String url,
        ImageView imageView) {
    BitmapDownloaderTask bitmapDownloaderTask = getBitmapDownloaderTask(imageView);

    if (bitmapDownloaderTask != null) {
        String bitmapUrl = bitmapDownloaderTask.url;
        if ((bitmapUrl == null) || (!bitmapUrl.equals(url))) {
            bitmapDownloaderTask.cancel(true);
        } else {
            // The same URL is already being downloaded.
            return false;
        }
    }
    return true;
}

// gets an existing download if one exists for the imageview
private static BitmapDownloaderTask getBitmapDownloaderTask(
        ImageView imageView) {
    if (imageView != null) {
        Drawable drawable = imageView.getDrawable();
        if (drawable instanceof DownloadedDrawable) {
            DownloadedDrawable downloadedDrawable = (DownloadedDrawable) drawable;
            return downloadedDrawable.getBitmapDownloaderTask();
        }
    }
    return null;
}

// our caching functions
// Find the dir to save cached images
private static File getCacheDirectory(Context context) {
    String sdState = android.os.Environment.getExternalStorageState();
    File cacheDir;

    if (sdState.equals(android.os.Environment.MEDIA_MOUNTED)) {
        File sdDir = android.os.Environment.getExternalStorageDirectory();

        // TODO : Change your diretcory here
        cacheDir = new File(sdDir, "data/ToDo/images");
    } else
        cacheDir = context.getCacheDir();

    if (!cacheDir.exists())
        cacheDir.mkdirs();
    return cacheDir;
}

private void writeFile(Bitmap bmp, File f) {
    FileOutputStream out = null;

    try {
        out = new FileOutputStream(f);
        bmp.compress(Bitmap.CompressFormat.PNG, 80, out);
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        try {
            if (out != null)
                out.close();
        } catch (Exception ex) {
        }
    }
}

// download asynctask
public class BitmapDownloaderTask extends AsyncTask<String, Void, Bitmap> {
    private String url;
    private final WeakReference<ImageView> imageViewReference;

    public BitmapDownloaderTask(ImageView imageView) {
        imageViewReference = new WeakReference<ImageView>(imageView);
    }

    @Override
    // Actual download method, run in the task thread
    protected Bitmap doInBackground(String... params) {
        // params comes from the execute() call: params[0] is the url.
        url = (String) params[0];
        return downloadBitmap(params[0]);
    }

    @Override
    // Once the image is downloaded, associates it to the imageView
    protected void onPostExecute(Bitmap bitmap) {
        if (isCancelled()) {
            bitmap = null;
        }

        if (imageViewReference != null) {
            ImageView imageView = imageViewReference.get();
            BitmapDownloaderTask bitmapDownloaderTask = getBitmapDownloaderTask(imageView);
            // Change bitmap only if this process is still associated with
            // it
            if (this == bitmapDownloaderTask) {
                imageView.setImageBitmap(bitmap);

                // cache the image

                String filename = String.valueOf(url.hashCode());
                File f = new File(
                        getCacheDirectory(imageView.getContext()), filename);

                imageCache.put(f.getPath(), bitmap);

                writeFile(bitmap, f);
            }
        }
    }

}

static class DownloadedDrawable extends ColorDrawable {
    private final WeakReference<BitmapDownloaderTask> bitmapDownloaderTaskReference;

    public DownloadedDrawable(BitmapDownloaderTask bitmapDownloaderTask) {
        super(Color.WHITE);
        bitmapDownloaderTaskReference = new WeakReference<BitmapDownloaderTask>(
                bitmapDownloaderTask);
    }

    public BitmapDownloaderTask getBitmapDownloaderTask() {
        return bitmapDownloaderTaskReference.get();
    }
}

// the actual download code
static Bitmap downloadBitmap(String url) {
    HttpParams params = new BasicHttpParams();
    params.setParameter(CoreProtocolPNames.PROTOCOL_VERSION,
            HttpVersion.HTTP_1_1);
    HttpClient client = new DefaultHttpClient(params);
    final HttpGet getRequest = new HttpGet(url);

    try {
        HttpResponse response = client.execute(getRequest);
        final int statusCode = response.getStatusLine().getStatusCode();
        if (statusCode != HttpStatus.SC_OK) {
            Log.w("ImageDownloader", "Error " + statusCode
                    + " while retrieving bitmap from " + url);
            return null;
        }

        final HttpEntity entity = response.getEntity();
        if (entity != null) {
            InputStream inputStream = null;
            try {
                inputStream = entity.getContent();
                final Bitmap bitmap = BitmapFactory
                        .decodeStream(inputStream);
                return bitmap;
            } finally {
                if (inputStream != null) {
                    inputStream.close();
                }
                entity.consumeContent();
            }
        }
    } catch (Exception e) {
        // Could provide a more explicit error message for IOException or
        // IllegalStateException
        getRequest.abort();
        Log.w("ImageDownloader", "Error while retrieving bitmap from "
                + url + e.toString());
    } finally {
        if (client != null) {
            // client.close();
        }
    }
    return null;
 }
}
Nikhil Gupta
quelle
4

Ich hatte dieses Problem und implementierte lruCache. Ich glaube, Sie benötigen API 12 und höher oder verwenden die kompatible v4-Bibliothek. lurCache ist ein schneller Speicher, hat aber auch ein Budget. Wenn Sie sich also Sorgen machen, können Sie einen Diskcache verwenden ... Alles wird unter Zwischenspeichern von Bitmaps beschrieben .

Ich werde jetzt meine Implementierung bereitstellen, bei der es sich um einen Singleton handelt, den ich von einem beliebigen Ort aus aufrufe:

//Where the first is a string and the other is a imageview to load.

DownloadImageTask.getInstance().loadBitmap(avatarURL, iv_avatar);

Hier ist der ideale Code zum Zwischenspeichern und Aufrufen des obigen Codes in getView eines Adapters beim Abrufen des Webbilds:

public class DownloadImageTask {

    private LruCache<String, Bitmap> mMemoryCache;

    /* Create a singleton class to call this from multiple classes */

    private static DownloadImageTask instance = null;

    public static DownloadImageTask getInstance() {
        if (instance == null) {
            instance = new DownloadImageTask();
        }
        return instance;
    }

    //Lock the constructor from public instances
    private DownloadImageTask() {

        // Get max available VM memory, exceeding this amount will throw an
        // OutOfMemory exception. Stored in kilobytes as LruCache takes an
        // int in its constructor.
        final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);

        // Use 1/8th of the available memory for this memory cache.
        final int cacheSize = maxMemory / 8;

        mMemoryCache = new LruCache<String, Bitmap>(cacheSize) {
            @Override
            protected int sizeOf(String key, Bitmap bitmap) {
                // The cache size will be measured in kilobytes rather than
                // number of items.
                return bitmap.getByteCount() / 1024;
            }
        };
    }

    public void loadBitmap(String avatarURL, ImageView imageView) {
        final String imageKey = String.valueOf(avatarURL);

        final Bitmap bitmap = getBitmapFromMemCache(imageKey);
        if (bitmap != null) {
            imageView.setImageBitmap(bitmap);
        } else {
            imageView.setImageResource(R.drawable.ic_launcher);

            new DownloadImageTaskViaWeb(imageView).execute(avatarURL);
        }
    }

    private void addBitmapToMemoryCache(String key, Bitmap bitmap) {
        if (getBitmapFromMemCache(key) == null) {
            mMemoryCache.put(key, bitmap);
        }
    }

    private Bitmap getBitmapFromMemCache(String key) {
        return mMemoryCache.get(key);
    }

    /* A background process that opens a http stream and decodes a web image. */

    class DownloadImageTaskViaWeb extends AsyncTask<String, Void, Bitmap> {
        ImageView bmImage;

        public DownloadImageTaskViaWeb(ImageView bmImage) {
            this.bmImage = bmImage;
        }

        protected Bitmap doInBackground(String... urls) {

            String urldisplay = urls[0];
            Bitmap mIcon = null;
            try {
                InputStream in = new java.net.URL(urldisplay).openStream();
                mIcon = BitmapFactory.decodeStream(in);

            } 
            catch (Exception e) {
                Log.e("Error", e.getMessage());
                e.printStackTrace();
            }

            addBitmapToMemoryCache(String.valueOf(urldisplay), mIcon);

            return mIcon;
        }

        /* After decoding we update the view on the main UI. */
        protected void onPostExecute(Bitmap result) {
            bmImage.setImageBitmap(result);
        }
    }
}
j2emanue
quelle