[android] 在ListView中延迟加载图像



Answers

我用图像做了一个懒惰列表 (位于GitHub) 的简单演示 。 这可能对某人有所帮助。 它在后台线程中下载图像。 图像被缓存在SD卡和内存中。 缓存实现非常简单,对于演示就足够了。 我使用inSampleSize解码图像以减少内存消耗。 我也尝试正确处理回收的视图。

Question

我正在使用ListView来显示与这些图像相关的一些图像和标题。 我从互联网上获取图像。 有没有办法在文本显示时延迟加载图像,UI未锁定并且图像在下载时显示?

图像总数不固定。




你必须试试这个Universal Loader是最好的。 在使用惰性加载完成许多RnD后,我正在使用这个功能。

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

特征

  • 多线程图像加载(异步或同步)
  • ImageLoader的配置(线程执行程序,下载程序,解码器,内存和磁盘缓存,显示图像选项等)的宽泛定制
  • 每个显示图像调用的许多自定义选项(存根图像,缓存切换,解码选项,位图处理和显示等)
  • Image caching in memory and/or on disk (device's file system or SD card)
  • Listening loading process (including downloading progress)

Android 2.0+ support







那么,来自互联网的图像加载时间有很多解决方案。 您也可以使用Android-Query库。 它会给你所有需要的活动。 确保你想要做什么,并阅读图书馆的维基页面。 并解决图片加载限制。

这是我的代码:

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

它应该解决你的延迟加载问题。




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.




我写了一篇教程,解释了如何在列表视图中执行延迟加载的图像。 我详细讨论了回收和并发问题。 我也使用固定线程池来防止产生大量线程。

Listview教程中的图像延迟加载




android-developers.blogspot.com/2010/07/… ,由Gilles Debunne编写的教程。

这来自Android开发人员博客。 建议的代码使用:

  • AsyncTasks
  • 一个硬的,有限的FIFO cache
  • 一个软,容易garbage collect缓存。
  • 占位符在下载时Drawable




这是Android上的一个常见问题,许多人已经以多种方式解决了这个问题。 在我看来,我见过的最好的解决方案是名为毕加索的相对较新的图书馆。 以下是亮点:

  • 开源,但由ActionBarSherlock成名的Jake Wharton领导。
  • 用一行代码异步加载来自网络或应用程序资源的图像
  • 自动ListView检测
  • 自动磁盘和内存缓存
  • 可以做自定义转换
  • 许多可配置的选项
  • 超级简单的API
  • 经常更新



我遵循这个Android培训,我认为它在下载图像方面做得非常出色,并且不会阻塞主UI。 它还处理缓存和处理滚动许多图像: 高效加载大型位图




我只想添加一个更好的示例,即XML适配器 。 由于它被Google使用,我也使用相同的逻辑来避免OutOfMemory错误。

基本上这个ImageDownloader是你的答案(因为它涵盖了你的大部分要求)。 有些你也可以在那里实现。




毕加索

使用杰克沃顿的毕加索图书馆。 (一个完美的ImageLoading库是ActionBarSherlock的开发者)

适用于Android的功能强大的图片下载和缓存库。

图像为Android应用程序添加了非常需要的上下文和视觉风格。 毕加索允许在应用程序中轻松加载图像 - 通常只需一行代码!

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

毕加索自动处理Android上图像加载的许多常见缺陷:

处理ImageView回收并在适配器中下载取消。 复杂的图像转换与最小的内存使用。 自动内存和磁盘缓存。

毕加索杰克沃顿图书馆

滑行

Glide是一款快速高效的Android开源媒体管理框架,将媒体解码,内存和磁盘缓存以及资源池整合到一个简单易用的界面中。

Glide支持获取,解码和显示视频静像,图像和动画GIF。 Glide包含一个灵活的API,允许开发人员插入几乎任何网络堆栈。 默认情况下,Glide使用基于自定义HttpUrlConnection的堆栈,但也包括实用程序库插入Google的Volley项目或Square的OkHttp库。

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

Glide的主要焦点是尽可能平滑和快速地滚动任何类型的图像列表,但对于几乎任何需要获取,调整大小和显示远程图像的情况,Glide都是有效的。

滑动图像加载库

通过Facebook的壁画

Fresco是一个在Android应用程序中显示图像的强大系统。

Fresco负责图像加载和显示,因此您不必这样做。 它将从网络,本地存储或本地资源中加载图像,并在图像到达之前显示一个占位符。 它有两个级别的缓存; 一个在内存中,另一个在内部存储器中。

壁画Github

在Android 4.x及更低版本中,Fresco将图像放在Android内存的特殊区域。 这可以让你的应用程序运行得更快 - 而且可怕的OutOfMemoryError遭受的次数更少。

壁画文件




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 developer.android.com/training/displaying-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<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);
        }
    }
}



Novoda also has a great lazy image loading library and many apps like Songkick, Podio, SecretDJ and ImageSearch use their library.

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.




使用滑翔库。它为我工作,并将为你的代码工作。它既适用于图像也适用于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);
}



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

举个例子:

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.




Links