Frage Lazy Laden von Bildern in ListView


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

Die Gesamtzahl der Bilder ist nicht festgelegt.


1731
2018-02-12 15:59


Ursprung


Antworten:


Hier ist, was ich erstellt habe, um die Bilder zu speichern, die meine App gerade anzeigt. Bitte beachten Sie, dass das "Log" -Objekt, das hier verwendet wird, mein benutzerdefinierter Wrapper für 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();
    }
}

1015
2018-02-18 03:56



ich machte eine einfache Demo einer faulen Liste (in GitHub) mit Bildern. Es kann für jemanden hilfreich sein. Es lädt Bilder im Hintergrundthread herunter. Bilder werden auf einer SD-Karte zwischengespeichert und gespeichert. Die Cache-Implementierung ist sehr einfach und reicht gerade für die Demo. Ich entschlüssle Bilder mit inSampleSize, um den Speicherverbrauch zu reduzieren. Ich versuche auch, recycelte Ansichten richtig zu behandeln.

Alt text


982
2018-06-18 08:04



Ich empfehle Open-Source-Instrument Universeller Bildlader. Es basiert ursprünglich auf Fedor Wlassows Projekt Faule Liste und wurde seitdem stark verbessert.

  • Laden von Multithread-Bildern
  • Möglichkeit der Konfiguration des ImageLoaders (Thread-Executor, Downlaoder, Decoder, Speicher- und Disk-Cache, Bildoptionen usw.)
  • Möglichkeit zum Zwischenspeichern von Bildern im Speicher und / oder auf dem Dateisystem des Geräts (oder SD-Karte)
  • Möglichkeit den Ladevorgang zu "hören"
  • Möglichkeit, jeden Bildanruf mit getrennten Optionen anzupassen
  • Widget-Unterstützung
  • Android 2.0+ Unterstützung


530
2017-12-19 13:53



Multithreading für Leistung, ein Tutorial von Gilles Debunne.

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

  • AsyncTasks.
  • Eine harte, begrenzte Größe, FIFO cache.
  • Ein weicher, leicht garbage collectCache.
  • EIN Platzhalter  Drawable während Sie herunterladen.

enter image description here


147
2017-08-12 11:07



Update: Beachten Sie, dass diese Antwort jetzt ziemlich ineffektiv ist. Der Garbage Collector reagiert aggressiv auf SoftReference und WeakReference, daher ist dieser Code NICHT für neue Apps geeignet.  (Versuchen Sie stattdessen Bibliotheken wie Universeller Bildlader in anderen Antworten vorgeschlagen.)

Danke an James für den Code und an 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 zu Müll gesammelt wurden. In meinem Fall war es ohne das SoftReference-Zeug gut, weil meine Listengröße begrenzt ist und meine Bilder klein sind.

Vor einem Jahr gab es eine Diskussion über die SoftReferences in Google Groups: Link zum Thema. Als Lösung für die zu frühe Garbage-Collection schlagen sie vor, die VM-Heap-Größe mit dalvik.system.VMRuntime.setMinimumHeapSize () manuell 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();
}

102
2018-05-05 13:16



Picasso 

Verwenden Sie Jake Whartons Picasso-Bibliothek. (Eine Perfect ImageLoading Library bildet den Entwickler von ActionBarSherlock)

Eine leistungsstarke Bild-Download- und Caching-Bibliothek für Android.

Bilder fügen Android-Anwendungen den dringend benötigten Kontext und das visuelle Flair hinzu. Picasso ermöglicht problemloses Laden von Bildern in Ihre Anwendung - oft in einer Codezeile!

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

Viele häufige Fallstricke beim Laden von Bildern auf Android werden automatisch von Picasso behandelt:

Behandlung von ImageView-Recycling und Download-Stornierung in einem Adapter. Komplexe Bildtransformationen mit minimaler Speicherbelegung Automatisches Speicher- und Festplatten-Caching

Picasso Jake Whartons Bibliothek

Gleiten

Glide ist ein schnelles und effizientes Open-Source-Media-Management-Framework für Android, das Medien-Decodierung, Speicher- und Festplatten-Caching sowie Ressourcen-Pooling in eine einfache und benutzerfreundliche Oberfläche integriert.

Glide unterstützt das Abrufen, Dekodieren und Anzeigen von Standbildern, Bildern und animierten GIFs. Glide enthält eine flexible API, die es Entwicklern ermöglicht, sich an fast jeden Netzwerkstapel anzuschließen. Standardmäßig verwendet Glide einen benutzerdefinierten HttpUrlConnection-basierten Stack, aber auch Utility-Bibliotheken, die stattdessen in Googles Volley-Projekt oder Squares OkHttp-Bibliothek eingefügt werden.

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

Glides Hauptaugenmerk liegt darauf, dass Sie jede Art von Bildliste so flüssig und schnell wie möglich scrollen können. Aber Glide ist auch für fast alle Fälle effektiv, in denen Sie ein Remote-Bild abrufen, skalieren und anzeigen müssen.

Glide Image Loading Bibliothek

Fresko von Facebook 

Fresco ist ein leistungsstarkes System zum Anzeigen von Bildern in Android-Anwendungen.

Fresco kümmert sich um das Laden und Anzeigen von Bildern, also müssen Sie nicht. Es lädt Bilder aus dem Netzwerk, lokalen Speicher oder lokalen Ressourcen und zeigt einen Platzhalter an, 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 eine spezielle Region von Android-Speicher. Dadurch kann Ihre Anwendung schneller ausgeführt werden - und der gefürchtete OutOfMemoryError viel seltener.

Fresko Dokumentation


84
2018-04-04 12:35



Hochleistungslader - nach Prüfung der hier vorgeschlagenen Methoden, ich benutzte Bens Lösung mit einigen Änderungen -

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

  2. Die Verwendung von SoftReference ist großartig, aber das zwischengespeicherte Bild wird zu oft gelöscht. Daher habe ich eine Verknüpfungsliste hinzugefügt, die Bildreferenzen enthält, die 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, was mir erlaubt, den Web-Cache zu benutzen (Sie müssen zuerst einen Antwort-Cache einstellen, 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;
}
}

77
2017-12-27 23:27



Ich habe dieses Android-Training verfolgt und finde es hervorragend, Bilder herunterzuladen, ohne die Hauptbenutzeroberfläche zu blockieren. Es behandelt auch das Caching und das Scrollen durch viele Bilder: Große Bitmaps effizient laden


75
2018-05-22 06:00