首页 文章

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

提问于
浏览
6

这是一种非常常见的情况:在ListView中显示必须从Internet下载的图像 .

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

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

  • getView()被调用
    产生

  • 线程以加载图像

  • 图像已加载;在ImageView上调用setImageDrawable()

  • ListView由于某种原因选择它并刷新自己

  • 为了刷新ListView,为每个可见行调用getView(),所以我们回到第1步,整个过程重复

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

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

4 回答

  • 3

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

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

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

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

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

  • 2

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

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

    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;
    }
    
  • 2

    我遇到过同样的问题 .

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

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

    2)在此 ImageView 覆盖方法

    @Override
    public void requestLayout()
    { 
      return; 
    }
    

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

    4)利润;)

  • 3

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

相关问题