android - Carga perezosa de imágenes en ListView




image url (20)

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

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


Bueno, el tiempo de carga de imágenes desde Internet tiene muchas soluciones. También puede utilizar la biblioteca Android-Query . Te dará toda la actividad requerida. Asegúrate de lo que quieres hacer y lee la página wiki de la biblioteca. Y resolver 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;
}

Se debe resolver su problema de carga perezosa.


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 dibujables es más rápido que con mapas de bits, así que en lugar de eso utilizo dibujables

  2. El uso de 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, impidiendo que la imagen se elimine, hasta que alcance un tamaño predefinido

  3. Para abrir InputStream, utilicé java.net.URLConnection, que me permite usar la caché web (primero debe configurar una caché de respuesta, 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<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;
}
}

Debes probar este cargador universal es el mejor. Estoy usando esto después de hacer muchos RnD en la carga perezosa.

github.com/nostra13/Android-Universal-Image-Loader

Caracteristicas

  • Carga de imágenes multiproceso (asíncrono o sincronizado)
  • Amplia personalización de la configuración de ImageLoader (ejecutores de hilos, descargador, decodificador, memoria y caché de disco, opciones de imagen de pantalla, etc.)
  • Muchas opciones de personalización para cada llamada de imagen de pantalla (imágenes de código auxiliar, interruptor de caché, opciones de decodificación, procesamiento y visualización de mapas de bits, etc.)
  • Almacenamiento 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 la descarga)

Soporte para Android 2.0+


Eche un vistazo a Shutterbug , el puerto ligero de SDWebImage (una biblioteca agradable en iOS) de Applidium para Android. Admite el almacenamiento en caché asíncrono, almacena direcciones 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!


Esto es lo que creé para contener las imágenes que mi aplicación está mostrando actualmente. Tenga en cuenta que el objeto "Log" en uso aquí es mi envoltorio 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<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();
    }
}

He escrito un tutorial que explica cómo realizar una carga lenta de imágenes en una vista de lista. Entro en algunos detalles sobre los temas de reciclaje y concurrencia. También utilizo un grupo de subprocesos fijos para evitar generar muchos subprocesos.

Carga perezosa de imágenes en Listview Tutorial


He seguido este entrenamiento de Android y creo que hace un excelente trabajo descargando imágenes sin bloquear la interfaz de usuario principal. También maneja el almacenamiento en caché y se ocupa del desplazamiento a través de muchas imágenes: Cargar mapas de bits grandes de manera eficiente


Hice una simple demostración 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 del 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 las vistas recicladas correctamente.


Recomiendo el instrumento de código abierto github.com/nostra13/Android-Universal-Image-Loader . Originalmente se basa en el proyecto LazyList de Fedor Vlasov y se ha mejorado enormemente desde entonces.

  • Carga de imágenes multiproceso
  • Posibilidad de ajuste amplio de la configuración de ImageLoader (ejecutores de subprocesos, decodificadores, decodificadores, memoria y caché de disco, opciones de imagen de pantalla, 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
  • Soporte de widgets
  • Soporte para Android 2.0+

github.com/nostra13/Android-Universal-Image-Loader


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 se pueden implementar en eso.


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

  • Utiliza un disco y memoria caché de uso menos reciente (LRU).
  • Decodifica eficientemente las imágenes.
  • Soporta la modificación de mapas de bits en subproceso de fondo.
  • Tiene un fundido cruzado simple.
  • Tiene una imagen cargando progreso de devolución de llamada.

Clone DroidPartsGram para un ejemplo:



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 su lugar, intente bibliotecas como github.com/nostra13/Android-Universal-Image-Loader sugiere en otras respuestas).

Gracias a James por el código, y Bao-Long por la sugerencia de usar SoftReference. Implementé los cambios de SoftReference en el código de James. Desafortunadamente, SoftReferences hizo que mis imágenes se recolectaran con demasiada rapidez. 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 las referencias de SoftReferences en los grupos de google: enlace al hilo . Como una solución para la recolección de basura demasiado temprana, sugieren la posibilidad de configurar manualmente el tamaño del montón de VM utilizando dalvik.system.VMRuntime.setMinimumHeapSize (), que no es muy atractivo para mí.

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();
}

Picasso

Usa la biblioteca de Picasso de Jake Wharton. (Una biblioteca de carga de imágenes perfecta del desarrollador de ActionBarSherlock)

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

Las imágenes agregan un contexto y un estilo visual muy necesarios a las aplicaciones de Android. Picasso permite la carga de imágenes sin problemas 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);

Picasso maneja automáticamente muchos de los inconvenientes comunes de la carga de imágenes en Android:

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

Biblioteca de Picasso Jake Wharton

Deslizamiento

Glide es un marco de administración de medios de código abierto rápido y eficiente para Android que envuelve la decodificación 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 captura, decodificación y visualización de imágenes fijas de video, imágenes y GIF animados. Glide incluye una api flexible que permite a los desarrolladores conectarse a casi cualquier pila de red. De manera predeterminada, Glide usa una pila personalizada basada en HttpUrlConnection, pero también incluye bibliotecas de utilidades conectadas al proyecto Volley de Google o a la biblioteca OkHttp de Square.

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

El objetivo principal de Glide es hacer que el desplazamiento de cualquier tipo de lista de imágenes sea lo más suave 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.

Imagen de deslizamiento cargando biblioteca

Fresco por Facebook

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

Fresco se encarga de cargar y mostrar la imagen, por lo que no tiene que hacerlo. 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.x e inferior, Fresco coloca las 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


Solo un consejo rápido para alguien que está en indecisión sobre qué biblioteca usar para las imágenes de carga lenta:

Hay cuatro formas básicas.

  1. DIY => No es la mejor solución pero para unas pocas imágenes y si quieres ir sin la molestia de usar otras bibliotecas

  2. Volley's Lazy Loading library => De chicos en Android. Es agradable y todo, pero está mal documentado y, por lo tanto, es un problema para usar.

  3. Picasso: una solución simple que simplemente funciona, incluso puede especificar el tamaño de imagen exacto que quiere traer. Es muy simple de usar pero puede no ser muy "eficaz" para aplicaciones que tienen que lidiar con enormes cantidades de imágenes.

  4. UIL: La mejor manera de cargar imágenes perezosas. Puede almacenar imágenes en caché (necesita permiso, por supuesto), inicializar el cargador una vez y luego hacer su trabajo. La biblioteca de carga asíncrona más madura que he visto hasta ahora.


Todos los códigos anteriores tienen su propio valor, pero con mi experiencia personal, solo pruébelo con Picasso.

Picasso es una biblioteca específicamente para este propósito, de hecho administrará el caché y todas las demás operaciones de red automáticamente. Deberá agregar una biblioteca en su proyecto y solo escribir una línea de código para cargar la imagen desde una URL remota.

Visite aquí: http://code.tutsplus.com/tutorials/android-sdk-working-with-picasso--cms-22149


Prueba Android-Query . Tiene métodos increíblemente simples para cargar y almacenar en caché las imágenes de forma asíncrona.


Revisa mi tenedor de LazyList . Básicamente, mejoro LazyList retrasando la llamada de ImageView y creo dos métodos:

  1. Cuando necesites poner algo como "Cargando imagen ..."
  2. Cuando necesites mostrar la imagen descargada.

También mejoré el ImageLoader al implementar un singleton en este objeto.


Tuve este problema e implementé lruCache. Creo que necesitas API 12 o superior o usar la biblioteca de compatibilidad v4. lurCache es una memoria rápida, pero también tiene un presupuesto, por lo que si le preocupa que pueda usar una caché de disco ... Todo se describe en developer.android.com/training/displaying-bitmaps/… .

Ahora proporcionaré mi implementación, que es un singleton que llamo desde cualquier lugar así:

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

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

Aquí está el código ideal para almacenar en caché y luego llamar a lo anterior en getView de un adaptador al recuperar la imagen web:

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

Usa la biblioteca de planeo. Funcionó para mí y también lo será para tu código. Funciona tanto para imágenes como para 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);
}




universal-image-loader