Android - 将图像延迟加载到ListView中的问题

时间:2009-09-11 08:07:38

标签: java android listview image lazy-loading

这是一种非常常见的情况:在ListView中显示必须从互联网上下载的图像。

现在我有一个ArrayAdapter的自定义子类,我将其用于ListView。在ArrayAdapter的getView()实现中,我生成了一个单独的线程来加载图像。加载完成后,它会查找相应的ImageView并使用ImageView.setImageDrawable()设置图像。所以我使用的解决方案与此类似:Lazy load of images in ListView

我遇到的问题是,只要我在ImageView上调用setImageDrawable(),ListView就会以某种方式刷新列表中当前可见的所有行!这导致了一种无限循环:

  1. getView()被称为
  2. 生成线程以加载图像
  3. 图片已加载;在ImageView
  4. 上调用setImageDrawable()
  5. ListView因某种原因选择它并自行刷新
  6. 为了刷新ListView,为每个可见行调用getView(),所以我们回到第1步,整个事情重复进行
  7. 据我所知,“Android中如何在ListView中对图像进行延迟加载”(参见上面的链接)中提出的解决方案根本不起作用。它可能看起来像它,但它会运行得非常慢,因为在后台,它会不断重新加载当前可见的行。

    之前是否有人遇到此问题和/或有解决方案?

4 个答案:

答案 0 :(得分:3)

我使用了以下链接中的代码:another stackoverflow question

我做了一些小改动以解决回收视图问题。我将图像的URL设置为适配器中的imageview标签。以下代码包含解决回收问题的解决方案:

public void fetchDrawableOnThread(final String urlString, final ImageView imageView,Drawable drw) {

    imageView.setImageDrawable(drw);//drw is default image
    if (drawableMap.containsKey(urlString)) {
        if(imageView.getTag().toString().equals(urlString))
        {
            imageView.setImageBitmap(drawableMap.get(urlString));
            imageView.invalidate();
            return;
        }

    }

    final Handler handler = new Handler() {
        @Override
        public void handleMessage(Message message) {
            BitmapWrapper wrapper = (BitmapWrapper)message.obj;
            if(wrapper.imageurl.equals(imageView.getTag().toString()))
            {
                imageView.setImageBitmap((Bitmap)wrapper.bitmap);
                imageView.invalidate();
            }

        }
    };

    Thread thread = new Thread() {
        @Override
        public void run() {
            //TODO : set imageView to a "pending" image

            Bitmap drawable = fetchDrawable(urlString);
            BitmapWrapper wrapper = new BitmapWrapper();
            wrapper.bitmap = drawable;
            wrapper.imageurl = urlString;
            Message message = handler.obtainMessage(1, wrapper);
            handler.sendMessage(message);
        }
    };
    thread.start();
}


    public class BitmapWrapper
{
    public Bitmap bitmap;
    public String imageurl;
}

答案 1 :(得分:3)

我遇到了同样的问题。

经过近2天的大量调试/优化并试图弄明白,为什么我的getView()在一行中使用setImageBitmap()时一遍又一遍地调用所有视图,我想出了一个肮脏的解决方案:

1)扩展您用于列表中所有图片的自定义ImageView

2)在此ImageView中覆盖方法

@Override
public void requestLayout()
{ 
  return; 
}

3)很脏,但对我来说它有效

4)利润;)

答案 2 :(得分:2)

在链接的解决方案中,只有在视图不具有正确的drawable时才应调用fetchDrawableOnThread()

如果getDrawable()返回null,则视图没有drawable。

如果您正在重复使用插槽,则表示您需要更进一步并管理状态。如果你的视图有一个存储URL的成员变量,并且有一个布尔值来表明它是否被加载,那么很容易知道是否要调用fetchDrawableOnThread(),例如。

我推测drawable的toString()详细说明了加载图像的路径。 (如果没有,你可以将返回的drawable子类化为如此)。在这种情况下,您可以避免上面列出的布尔值,只是进行比较以确定它是否是正确的drawable或是否获取替换。

此外,可见行上的getView()应确保不再可见的那些被卸载,以防止内存耗尽。一个技巧就是将不再可见的图像移动到软引用(因此在需要内存时将它们卸载)作为原始线程上的另一张海报。

答案 3 :(得分:2)

我有一个ThumbnailAdapter,它包含了可能有用的整个模式。