7

这是一个非常常见的场景:在 ListView 中显示必须从 Internet 下载的图像。

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

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

  1. 调用 getView()
  2. 产生线程以加载图像
  3. 图像已加载;在 ImageView 上调用 setImageDrawable()
  4. ListView 出于某种原因将其拾取并自行刷新
  5. 为了让 ListView 刷新,每个可见行都会调用 getView(),所以我们回到第 1 步,整个事情会不断重复

据我所知,“Android - 如何在 ListView 中延迟加载图像”(见上面的链接)中提出的解决方案根本不起作用。它可能看起来确实如此,但它会运行得很慢,因为在后台,它会不断重新加载当前可见的行。

有没有人遇到过这个问题和/或有解决方案?

4

4 回答 4

4

我在以下链接中使用了代码: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;
}
于 2011-03-23T20:58:15.567 回答
4

我遇到过同样的问题。

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

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

2)在此ImageView覆盖方法

@Override
public void requestLayout()
{ 
  return; 
}

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

4) 利润 ;)

于 2012-03-07T13:32:32.147 回答
3

在链接的解决方案中,fetchDrawableOnThread()只有在视图还没有正确的可绘制对象时才应该调用。

getDrawable()如果返回 null,则视图没有可绘制对象。

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

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

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

于 2009-09-11T08:34:50.070 回答
2

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

于 2009-09-11T10:43:33.773 回答