Vraag Luie hoeveelheid afbeeldingen in ListView


Ik gebruik een ListView om enkele afbeeldingen en bijschriften weer te geven die aan die afbeeldingen zijn gekoppeld. Ik krijg de afbeeldingen van internet. Is er een manier om de beelden lui te laden, terwijl de tekst wordt weergegeven, de gebruikersinterface niet is vergrendeld en de afbeeldingen worden weergegeven terwijl ze worden gedownload?

Het totale aantal afbeeldingen staat niet vast.


1731
2018-02-12 15:59


oorsprong


antwoorden:


Dit is wat ik heb gemaakt om de afbeeldingen te bevatten die mijn app momenteel weergeeft. Let op: het "Log" -object dat hier wordt gebruikt, is mijn aangepaste wrapper rond de laatste Log-klasse in 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();
    }
}

1015
2018-02-18 03:56



ik maakte een eenvoudige demo van een luie lijst (bevindt zich op GitHub) met afbeeldingen. Het kan voor iemand nuttig zijn. Het downloadt afbeeldingen in de achtergrondthread. Afbeeldingen worden in de cache opgeslagen op een SD-kaart en in het geheugen. De cache-implementatie is heel eenvoudig en is net genoeg voor de demo. Ik decodeer afbeeldingen met inSampleSize om het geheugengebruik te verminderen. Ik probeer ook gerecyclede weergaven correct te behandelen.

Alt text


982
2018-06-18 08:04



Ik raad een open source-instrument aan Universal Image Loader. Het is oorspronkelijk gebaseerd op het project van Fedor Vlasov Luie lijst en is sindsdien enorm verbeterd.

  • Multithread beeld laden
  • Mogelijkheid om ImageLoader's configuratie (thread-uitvoeringen, down-lader, decoder, geheugen en schijfcache, weergave-afbeeldingsopties en andere) breed af te stemmen
  • Mogelijkheid van beeldcaching in het geheugen en / of op het bestandssysteem van het apparaat (of SD-kaart)
  • Mogelijkheid om het laadproces te "luisteren"
  • Mogelijkheid om elke display-afbeelding aan te passen met afzonderlijke opties
  • Widget-ondersteuning
  • Ondersteuning voor Android 2.0+


530
2017-12-19 13:53



Multithreading voor prestaties, een tutorial van Gilles Debunne.

Dit komt van de Android Developers-blog. De voorgestelde code gebruikt:

  • AsyncTasks.
  • Een harde, beperkte maat, FIFO cache.
  • Een zacht, gemakkelijk garbage collectcache.
  • EEN placeholder  Drawable terwijl je downloadt.

enter image description here


147
2017-08-12 11:07



Update: houd er rekening mee dat dit antwoord nu behoorlijk ineffectief is. The Garbage Collector werkt agressief op SoftReference en WeakReference, dus deze code is NIET geschikt voor nieuwe apps.  (Probeer liever bibliotheken Universal Image Loader voorgesteld in andere antwoorden.)

Dank aan James voor de code, en Bao-Long voor de suggestie om SoftReference te gebruiken. Ik heb de SoftReference-wijzigingen op de code van James geïmplementeerd. Helaas zorgde SoftReferences ervoor dat mijn afbeeldingen te snel werden verzameld. In mijn geval was het prima zonder de SoftReference-dingen, omdat mijn lijstgrootte beperkt is en mijn afbeeldingen klein zijn.

Er is een discussie van een jaar geleden over de SoftReferences op google-groepen: link naar thread. Als een oplossing voor de te vroege garbagecollection, suggereren ze de mogelijkheid om de VM-heapgrootte handmatig in te stellen met dalvik.system.VMRuntime.setMinimumHeapSize (), wat niet erg aantrekkelijk voor me is.

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 

Gebruik de Picasso-bibliotheek van Jake Wharton. (Een Perfect ImageLoading Library vormt de ontwikkelaar van ActionBarSherlock)

Een krachtige bibliotheek voor het downloaden en cachen van afbeeldingen voor Android.

Afbeeldingen voegen de broodnodige context en visuele flair toe aan Android-applicaties. Picasso zorgt voor probleemloos laden van afbeeldingen in uw applicatie - vaak in één regel code!

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

Veel voorkomende valkuilen bij het laden van afbeeldingen op Android worden automatisch afgehandeld door Picasso:

ImageView-recycling en downloadannulering in een adapter verwerken. Complexe beeldtransformaties met minimaal geheugengebruik. Automatisch geheugen en schijfcaching.

Picasso Jake Wharton's Library

Glijden

Glide is een snel en efficiënt open source media management framework voor Android dat media decodering, geheugen en disk caching en resource pooling omspant in een eenvoudige en makkelijk te gebruiken interface.

Glide ondersteunt het ophalen, decoderen en weergeven van stilstaande beelden, afbeeldingen en geanimeerde GIF's. Glide bevat een flexibele api waarmee ontwikkelaars kunnen aansluiten op vrijwel elke netwerkstack. Glide gebruikt standaard een aangepaste op HttpUrlConnection gebaseerde stack, maar bevat ook hulpprogramma-bibliotheken die in plaats daarvan verbinding maken met het Volley-project van Google of de OkHttp-bibliotheek van Square.

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

Glide richt zich in eerste instantie op het zo soepel en snel mogelijk scrollen van elke soort lijst met afbeeldingen, maar Glide is ook effectief voor bijna elk geval waarin u een externe afbeelding moet ophalen, vergroten of verkleinen en weergeven.

Glide Image Loading Library

Fresco door Facebook 

Fresco is een krachtig systeem voor het weergeven van afbeeldingen in Android-applicaties.

Fresco zorgt voor het laden en weergeven van afbeeldingen, dus dat hoeft niet. Het laadt afbeeldingen van het netwerk, lokale opslag of lokale bronnen en geeft een tijdelijke aanduiding weer tot de afbeelding is aangekomen. Het heeft twee niveaus van cache; een in het geheugen en een andere in interne opslag.

Fresco Github

In Android 4.x en lager plaatst Fresco afbeeldingen in een speciale regio van het Android-geheugen. Hierdoor kan uw toepassing sneller worden uitgevoerd en wordt de gevreesde OutOfMemoryError veel minder vaak verdragen.

Fresco-documentatie


84
2018-04-04 12:35



Krachtige lader - na onderzoek van de hier voorgestelde methoden, ik gebruikte Ben's oplossing met enkele wijzigingen -

  1. Ik besefte dat het werken met drawables sneller gaat dan met bitmaps dus ik gebruik in plaats daarvan drawables

  2. Het gebruik van SoftReference is geweldig, maar het maakt de afbeelding in de cache te vaak verwijderd, daarom heb ik een gelinkte lijst toegevoegd die referenties van afbeeldingen bevat, waardoor de afbeelding niet kan worden verwijderd totdat deze een vooraf gedefinieerde grootte heeft bereikt

  3. Om de InputStream te openen heb ik java.net.URLConnection gebruikt waarmee ik web cache kan gebruiken (je moet eerst een response cache instellen, maar dat is een ander verhaal)

Mijn 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



Ik heb deze Android-training gevolgd en ik denk dat het uitstekend werkt bij het downloaden van afbeeldingen zonder de hoofdgebruikersinterface te blokkeren. Het behandelt ook caching en het omgaan met scrollen door veel afbeeldingen: Grote bitmaps efficiënt laden


75
2018-05-22 06:00



1.  Picasso zorgt voor probleemloos laden van afbeeldingen in uw toepassing - vaak in één regel code!

Gebruik Gradle:

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

Slechts één regel code!

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

2.  Glijden Een beeldladende en cachebibliotheek voor Android was gericht op soepel scrollen

Gebruik Gradle:

repositories {
  mavenCentral() 
  google()
}

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

// Voor een eenvoudige weergave:

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

3.  fresco  is een krachtig systeem voor het weergeven van afbeeldingen op Android    applications.Fresco zorgt voor het laden en weergeven van afbeeldingen, dus u hebt dit niet   naar.

Aan de slag met Fresco


56
2017-08-27 12:54



Ik heb een zelfstudie geschreven waarin wordt uitgelegd hoe je foto's lazy-laadt in een lijstweergave. Ik ga in detail in op de kwestie van recycling en concurrency. Ik gebruik ook een pool met vaste schroefdraad om te voorkomen dat veel threads worden uitgezet.

Lui beeld laden in Listview-zelfstudie


50
2018-02-12 20:07