Carga lenta de imágenes en ListView

Estoy usando un ListView para mostrar algunas imágenes y títulos asociados con esas imágenes. Obtengo las imágenes de Internet. ¿Hay alguna forma de cargar las imágenes de forma perezosa, de modo que mientras se muestra el texto, la IU no está bloqueada y las imágenes se muestran a medida que se descargan?

El número total de imágenes no es fijo.

Esto es lo que creé para guardar las imágenes que mi aplicación muestra actualmente. Tenga en cuenta que el objeto “Log” en uso aquí es mi contenedor personalizado alrededor de la clase Log final dentro de 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 drawableMap; public DrawableManager() { drawableMap = new HashMap(); } 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(); } } 

Hice una demostración simple de una lista perezosa (ubicada en GitHub) con imágenes. Puede ser útil para alguien. Descarga imágenes en el hilo de fondo. Las imágenes se almacenan en caché en una tarjeta SD y en la memoria. La implementación de la memoria caché es muy simple y es suficiente para la demostración. Decodifico imágenes con inSampleSize para reducir el consumo de memoria. También trato de manejar vistas recicladas correctamente.

texto alternativo

Recomiendo el instrumento de fuente abierta Universal Image Loader . Originalmente se basa en el proyecto LazyList de Fedor Vlasov y ha mejorado mucho desde entonces.

  • Carga de imágenes multiproceso
  • Posibilidad de ajuste amplio de la configuración de ImageLoader (ejecutores de subprocesos, downlaoder, decodificador, caché de memoria y disco, opciones de visualización de imágenes y otros)
  • Posibilidad de almacenamiento en caché de imágenes en la memoria y / o en el sistema de archivos del dispositivo (o tarjeta SD)
  • Posibilidad de “escuchar” el proceso de carga
  • Posibilidad de personalizar cada llamada de imagen de pantalla con opciones separadas
  • Compatibilidad con widgets
  • Soporte para Android 2.0+

Multithreading For Performance , un tutorial de Gilles Debunne.

Esto es del Blog de Desarrolladores de Android. El código sugerido usa:

  • AsyncTasks .
  • Un FIFO cache duro y de tamaño limitado.
  • Una memoria caché garbage collect suave y fácil de desechar.
  • Un marcador de posición Drawable mientras descarga.

enter image description here

Actualización: tenga en cuenta que esta respuesta es bastante ineficaz ahora. El recolector de basura actúa agresivamente en SoftReference y WeakReference, por lo que este código NO es adecuado para nuevas aplicaciones. (En cambio, pruebe con bibliotecas como Universal Image Loader sugeridas en otras respuestas).

Gracias a James por el código y a Bao-Long por la sugerencia de usar SoftReference. Implementé los cambios de SoftReference en el código de James. Lamentablemente, SoftReferences causó que mis imágenes se recogieran basura demasiado rápido. En mi caso, estuvo bien sin las cosas de SoftReference, porque el tamaño de mi lista es limitado y mis imágenes son pequeñas.

Hay una discusión de hace un año sobre SoftReferences en grupos de google: link to thread . Como solución a la recolección de basura demasiado temprana, sugieren la posibilidad de establecer manualmente el tamaño del almacenamiento dynamic de la máquina virtual utilizando dalvik.system.VMRuntime.setMinimumHeapSize (), lo cual no es muy atractivo para mí.

 public DrawableManager() { drawableMap = new HashMap>(); } public Drawable fetchDrawable(String urlString) { SoftReference 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); 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 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(); } 

Picasso

Utiliza la Biblioteca Picasso de Jake Wharton. (Una biblioteca Perfect ImageLoading es el desarrollador de ActionBarSherlock)

Una potente biblioteca de descarga y almacenamiento en caché de imágenes para Android.

Las imágenes agregan un contexto muy necesario y un toque visual a las aplicaciones de Android. Picasso permite cargar imágenes sin inconvenientes en su aplicación, ¡a menudo en una línea de código!

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

Muchas de las trampas comunes de la carga de imágenes en Android son manejadas automáticamente por Picasso:

Manejo del reciclaje de ImageView y cancelación de descarga en un adaptador. Transformaciones de imagen complejas con uso mínimo de memoria. Memoria automática y almacenamiento en caché de disco.

Biblioteca de Picasso Jake Wharton

Planeo

Glide es un marco de gestión de medios de código abierto rápido y eficiente para Android que integra la deencoding de medios, la memoria y el almacenamiento en caché de disco, y la agrupación de recursos en una interfaz simple y fácil de usar.

Glide admite la búsqueda, la deencoding y la visualización de imágenes fijas, videos y GIF animados. Glide incluye una API flexible que permite a los desarrolladores conectarse a casi cualquier stack de red. Por defecto, Glide usa una stack basada en HttpUrlConnection personalizada, pero también incluye bibliotecas de utilidades que se conectan al proyecto Volley de Google o a la biblioteca OkHttp de Square.

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

El objective principal de Glide es hacer que el desplazamiento de cualquier tipo de lista sea lo más fácil y rápido posible, pero Glide también es efectivo para casi cualquier caso en el que necesite buscar, cambiar el tamaño y mostrar una imagen remota.

Glide Image Loading Library

Fresco por Facebook

Fresco es un poderoso sistema para mostrar imágenes en aplicaciones de Android.

Fresco se encarga de la carga y visualización de la imagen, por lo que no es necesario. Cargará imágenes de la red, el almacenamiento local o los recursos locales, y mostrará un marcador de posición hasta que la imagen haya llegado. Tiene dos niveles de caché; uno en memoria y otro en almacenamiento interno.

Fresco Github

En Android 4.xy versiones anteriores, Fresco coloca imágenes en una región especial de la memoria de Android. Esto permite que su aplicación se ejecute más rápido y sufra el temido OutOfMemoryError con mucha menos frecuencia.

Documentación Fresco

Cargador de alto rendimiento: después de examinar los métodos sugeridos aquí, utilicé la solución de Ben con algunos cambios:

  1. Me di cuenta de que trabajar con herramientas arrastrables es más rápido que con mapas de bits, así que utilizo herramientas deslizables en su lugar

  2. Usar SoftReference es genial, pero hace que la imagen almacenada en caché se elimine con demasiada frecuencia, así que agregué una lista vinculada que contiene referencias de imágenes, evitando que la imagen sea eliminada, hasta que alcanzó un tamaño predefinido

  3. Para abrir el InputStream utilicé java.net.URLConnection, que me permite usar el caché web (primero debe establecer un caché de respuestas, pero esa es otra historia)

Mi código:

 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> mCache = new HashMap>(); private final LinkedList  mChacheController = new LinkedList  (); private ExecutorService mThreadPool; private final Map mImageViews = Collections.synchronizedMap(new WeakHashMap()); 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)); } 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; } } 

Seguí este entrenamiento de Android y creo que hace un excelente trabajo al descargar imágenes sin bloquear la interfaz de usuario principal. También maneja el almacenamiento en caché y trata de desplazarse por muchas imágenes: carga de mapas de bits de manera eficiente

1. Picasso permite una carga de imágenes sin complicaciones en su aplicación, ¡a menudo en una línea de código!

Usa Gradle:

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

¡Solo una línea de código!

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

2. Glide Una biblioteca de carga de imágenes y caché para Android centrada en el desplazamiento suave

Usa Gradle:

 repositories { mavenCentral() google() } dependencies { implementation 'com.github.bumptech.glide:glide:4.7.1' annotationProcessor 'com.github.bumptech.glide:compiler:4.7.1' } 

// Para una vista simple:

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

3. fresco es un poderoso sistema para mostrar imágenes en aplicaciones de Android . Fresco se encarga de la carga y visualización de la imagen, por lo que no es necesario.

Comenzando con Fresco

He escrito un tutorial que explica cómo hacer la carga lenta de imágenes en una vista de lista. Entre en detalles sobre los problemas del reciclaje y la concurrencia. También uso un grupo de subprocesos fijos para evitar generar muchos subprocesos.

Carga lenta de imágenes en Listview Tutorial

La forma en que lo hago es lanzando un hilo para descargar las imágenes en segundo plano y darle una callback para cada elemento de la lista. Cuando termina de descargar una imagen, llama a la callback que actualiza la vista del elemento de la lista.

Sin embargo, este método no funciona muy bien cuando reciclas vistas.

Solo quiero agregar un buen ejemplo más, Adaptadores XML . Como lo usa Google y también estoy usando la misma lógica para evitar un error de OutOfMemory.

Básicamente este ImageDownloader es su respuesta (ya que cubre la mayoría de sus requisitos). Algunos también pueden implementar eso.

He estado usando NetworkImageView desde la nueva Biblioteca de Volley de Android com.android.volley.toolbox.NetworkImageView , y parece estar funcionando bastante bien. Aparentemente, esta es la misma vista que se usa en Google Play y otras aplicaciones nuevas de Google. Definitivamente vale la pena echarle un vistazo.

  • Tutorial de caché de imágenes de volley de Google I / O 2013

  • Desarrolladores Eventos de Google

Este es un problema común en Android que muchas personas han resuelto de muchas maneras. En mi opinión, la mejor solución que he visto es la biblioteca relativamente nueva llamada Picasso . Estos son los aspectos más destacados:

  • De código abierto, pero encabezado por Jake Wharton de la fama de ActionBarSherlock .
  • Cargue de forma asíncrona imágenes de la red o recursos de la aplicación con una línea de código
  • Detección automática de ListView
  • Almacenamiento en memoria caché automático de memoria y disco
  • Puede hacer transformaciones personalizadas
  • Muchas opciones configurables
  • API super simple
  • Actualizada frecuentemente

Creo que este problema es muy popular entre los desarrolladores de Android, y hay muchas bibliotecas que afirman resolver este problema, pero solo algunas parecen estar en la mira. AQuery es una de esas bibliotecas, pero es mejor que la mayoría en todos los aspectos y vale la pena intentarlo.

Bueno, el tiempo de carga de imágenes desde Internet tiene muchas soluciones. También puede usar la biblioteca Android-Query . Le dará toda la actividad requerida. Asegúrate de lo que quieres hacer y lee la página wiki de la biblioteca. Y resuelve la restricción de carga de la imagen.

Este es mi código:

 @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; } 

Debería resolver su problema de carga lenta.

Eche un vistazo a Shutterbug , el ligero puerto SDWebImage (una bonita biblioteca en iOS) de Applidium para Android. Admite el almacenamiento en caché asíncrono, almacena URL fallidas, maneja bien la concurrencia y se incluyen subclases útiles.

Las solicitudes de extracción (y los informes de errores) también son bienvenidos.

Debe probar que este Universal Loader es el mejor. Estoy usando esto después de hacer muchos RnD en carga lenta.

Universal Image Loader

Caracteristicas

  • Carga de imágenes de subprocesos múltiples (sincronización o sincronización)
  • Amplia personalización de la configuración de ImageLoader (ejecutores de subprocesos, descargador, decodificador, memoria y caché de disco, opciones de visualización de imágenes, etc.)
  • Muchas opciones de personalización para cada llamada de imagen en pantalla (imágenes de relleno, interruptor de almacenamiento en caché, opciones de deencoding, procesamiento y visualización de bitmap, etc.)
  • Almacenamiento en caché de imágenes en la memoria y / o en el disco (sistema de archivos del dispositivo o tarjeta SD)
  • Proceso de carga de escucha (incluido el progreso de descarga)

Soporte para Android 2.0+

enter image description here

DroidParts tiene ImageFetcher que requiere cero configuración para comenzar.

  • Utiliza un disco y memoria en la memoria caché utilizada menos recientemente (LRU).
  • Decodifica de manera eficiente las imágenes.
  • Admite la modificación de mapas de bits en el hilo de fondo.
  • Tiene simple cross-fade.
  • Tiene devolución de progreso de carga de imagen.

Clone DroidPartsGram para ver un ejemplo:

Ingrese la descripción de la imagen aquí

Novoda también tiene una gran biblioteca de carga de imágenes diferida y muchas aplicaciones como Songkick, Podio, SecretDJ e ImageSearch utilizan su biblioteca.

Their library is hosted here on Github and they have a pretty active issues tracker as well. Their project seems to be pretty active too, with over 300+ commits at the time of writing this reply.

Just a quick tip for someone who is in indecision regarding what library to use for lazy-loading images:

There are four basic ways.

  1. DIY => Not the best solution but for a few images and if you want to go without the hassle of using others libraries

  2. Volley’s Lazy Loading library => From guys at android. It is nice and everything but is poorly documented and hence is a problem to use.

  3. Picasso: A simple solution that just works, you can even specify the exact image size you want to bring in. It is very simple to use but might not be very “performant” for apps that has to deal with humongous amounts of images.

  4. UIL: The best way to lazy load images. You can cache images(you need permission of course), initialize the loader once, then have your work done. The most mature asynchronous image loading library I have ever seen so far.

Check my fork of LazyList . Basically, I improve the LazyList by delaying the call of the ImageView and create two methods:

  1. When you need to put something like “Loading image…”
  2. When you need to show the downloaded image.

I also improved the ImageLoader by implementing a singleton in this object.

All above code have their own worth but with my personal experience just give a try with Picasso.

Picasso is a library specifically for this purpose, in-fact it will manage cache and all other network operations automatically.You will have to add library in your project and just write a single line of code to load image from remote URL.

Please visit here : http://code.tutsplus.com/tutorials/android-sdk-working-with-picasso–cms-22149

I can recommend a different way that works like a charm: Android Query.

You can download that JAR file from here

 AQuery androidAQuery = new AQuery(this); 

Como ejemplo:

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

It’s very fast and accurate, and using this you can find many more features like animation when loading, getting a bitmap (if needed), etc.

Give Aquery a try. It has amazingly simple methods to load and cache images asynchronously.

URLImageViewHelper is an amazing library that helps you to do that.

Use the glide library. It worked for me and will work for your code too.It works for both images as well as gifs too.

 ImageView imageView = (ImageView) findViewById(R.id.test_image); GlideDrawableImageViewTarget imagePreview = new GlideDrawableImageViewTarget(imageView); Glide .with(this) .load(url) .listener(new RequestListener() { @Override public boolean onException(Exception e, String model, Target target, boolean isFirstResource) { return false; } @Override public boolean onResourceReady(GlideDrawable resource, String model, Target target, boolean isFromMemoryCache, boolean isFirstResource) { return false; } }) .into(imagePreview); } 
 public class ImageDownloader { Map imageCache; public ImageDownloader() { imageCache = new HashMap(); } // 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 { private String url; private final WeakReference imageViewReference; public BitmapDownloaderTask(ImageView imageView) { imageViewReference = new WeakReference(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 bitmapDownloaderTaskReference; public DownloadedDrawable(BitmapDownloaderTask bitmapDownloaderTask) { super(Color.WHITE); bitmapDownloaderTaskReference = new WeakReference( 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; } } 

I had this issue and implemented lruCache. I believe you need API 12 and above or use the compatiblity v4 library. lurCache is fast memory, but it also has a budget, so if you’re worried about that you can use a diskcache… It’s all described in Caching Bitmaps .

I’ll now provide my implementation which is a singleton I call from anywhere like this:

 //Where the first is a string and the other is a imageview to load. DownloadImageTask.getInstance().loadBitmap(avatarURL, iv_avatar); 

Here’s the ideal code to cache and then call the above in getView of an adapter when retrieving the web image:

 public class DownloadImageTask { private LruCache 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(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 { 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); } } } 

You can try the Aquery Android library for lazy loading image and listview… The below code may help you….. download library from here .

 AQuery aq = new AQuery(mContext); aq.id(R.id.image1).image("http://data.whicdn.com/images/63995806/original.jpg");