Ленивая загрузка изображений в ListView - PullRequest
1845 голосов
/ 12 февраля 2009

Я использую ListView для отображения некоторых изображений и подписей, связанных с этими изображениями. Я получаю изображения из Интернета. Есть ли способ ленивой загрузки изображений, чтобы при отображении текста пользовательский интерфейс не блокировался и изображения отображались по мере загрузки?

Общее количество изображений не фиксировано.

Ответы [ 39 ]

15 голосов
/ 12 января 2013

Novoda также имеет отличную ленивую библиотеку загрузки изображений , и многие приложения, такие как Songkick, Podio, SecretDJ и ImageSearch, используют свою библиотеку.

Их библиотека размещена здесь на Github, и у них также есть довольно активный трекер проблем . Их проект, кажется, тоже довольно активен: более 300 коммитов на момент написания этого ответа.

13 голосов
/ 13 февраля 2013

Проверьте мой форк LazyList . По сути, я улучшаю LazyList, задерживая вызов ImageView и создаю два метода:

  1. Когда нужно поставить что-то вроде «Загрузка изображения ...»
  2. Когда вам нужно показать загруженное изображение.

Я также улучшил ImageLoader, добавив singleton в этот объект.

11 голосов
/ 09 июля 2015

Все вышеприведенные коды имеют свою ценность, но с моим личным опытом просто попробуйте с Пикассо.

Picasso - это библиотека, специально предназначенная для этой цели, фактически она будет автоматически управлять кэшем и всеми другими сетевыми операциями. Вам нужно будет добавить библиотеку в свой проект и просто написать одну строку кода загрузить изображение с удаленного URL.

Пожалуйста, посетите здесь: http://code.tutsplus.com/tutorials/android-sdk-working-with-picasso--cms-22149

9 голосов
/ 16 марта 2017

Используйте библиотеку скольжения. Это сработало для меня и будет работать для вашего кода. Это работает как для изображений, так и для GIF-файлов.

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);
}
9 голосов
/ 26 февраля 2018

Если вы хотите отобразить макет Shimmer, такой как Facebook, для этого есть официальная библиотека Facebook. FaceBook Shimmer Android

Он обо всем позаботится, вам просто нужно поместить желаемый код дизайна в виде мерцающей рамки. Вот пример кода.

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

 <here will be your content to display />

</com.facebook.shimmer.ShimmerFrameLayout>

И вот код Java для него.

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

Добавьте эту зависимость в ваш файл Gradle.

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

Вот как это выглядит. Shimmer Android screenshot

7 голосов
/ 27 января 2014

URLImageViewHelper - удивительная библиотека, которая поможет вам сделать это.

7 голосов
/ 16 декабря 2013

Дайте Aquery попробовать. Он имеет удивительно простые методы для асинхронной загрузки и кэширования изображений.

7 голосов
/ 29 июля 2013

Я могу порекомендовать другой способ, который работает как шарм: Android Query.

Вы можете скачать этот JAR файл с здесь

AQuery androidAQuery = new AQuery(this);

Как пример:

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

Это очень быстро и точно, и с его помощью вы можете найти много других функций, таких как анимация при загрузке, получение растрового изображения (при необходимости) и т. Д.

4 голосов
/ 18 июля 2013
public class ImageDownloader {

Map<String, Bitmap> imageCache;

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

}

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

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

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

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

        if (bitmap == null) {

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

                // cache the image

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

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

                writeFile(bitmap, f);
            }
        }
    }

}

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

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

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

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

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

        final HttpEntity entity = response.getEntity();
        if (entity != null) {
            InputStream inputStream = null;
            try {
                inputStream = entity.getContent();
                final Bitmap bitmap = BitmapFactory
                        .decodeStream(inputStream);
                return bitmap;
            } finally {
                if (inputStream != null) {
                    inputStream.close();
                }
                entity.consumeContent();
            }
        }
    } catch (Exception e) {
        // Could provide a more explicit error message for IOException or
        // IllegalStateException
        getRequest.abort();
        Log.w("ImageDownloader", "Error while retrieving bitmap from "
                + url + e.toString());
    } finally {
        if (client != null) {
            // client.close();
        }
    }
    return null;
 }
}
4 голосов
/ 03 сентября 2013

Вы можете попробовать библиотеку Aquery Android для отложенной загрузки изображений и просмотра списка ... Следующий код может помочь вам ..... скачать библиотеку здесь .

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