繁体   English   中英

多线程缓存的imageView加载

[英]Multithreaded cached imageView loading

我从人们制作的一些主要缓存/图像加载方法中摘录了一部分,并提出了一些使用浏览器缓存并非常快速地加载图像的方法。

我的问题是,有时图像不正确(与另一个图像重复),当我向下滚动imageViews列表时,图像闪烁并随着滚动而变化。 这是我必须忍受的吗?

是的,我为每个imageView创建一个新线程。 我在队列中尝试了一个线程,因此加载时间太长。 即使它们都是单独的线程,也不应使用错误的drawable加载imageView。

这是我的代码。

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

    if (imageView != null && urlString != null && urlString.length() > 0)
    {

        final Handler handler = new Handler() {
            @Override
            public void handleMessage(Message message) {
                imageView.setImageDrawable((Drawable) message.obj);
            }
        };

        Thread thread = new Thread() {
            @Override
            public void run() {
                if (imageView != null && urlString != null && !urlString.equals(""))
                {
                    URL url;
                    try {
                        InputStream is = fetch(urlString);

                        if (is != null) {
                            Drawable drawable = Drawable.createFromStream((InputStream)is, "src");
                            Message message = handler.obtainMessage(1, drawable);
                            handler.sendMessage(message);
                        } 
                    }
                    catch (MalformedURLException e) {
                        Log.e(this.getClass().getSimpleName(), "fetchDrawable failed", e);
                    } catch (IOException e) {
                        Log.e(this.getClass().getSimpleName(), "fetchDrawable failed", e);
                    }
                }

            }
        };
        thread.start();
    }

}

private InputStream fetch(String urlString) throws MalformedURLException, IOException {
    if (urlString != null)
    {
        URL url = new URL(urlString);

        URLConnection connection = url.openConnection();
        connection.setUseCaches(true);
        Object response = connection.getContent();
        if (response instanceof InputStream) {
            return (InputStream) response;
        }
    }
    return null;
}

* 编辑 ***

毕竟所有评论都是我的代码:我目前正在获取05-19 00:16:49.535:ERROR / AndroidRuntime(12213):java.lang.RuntimeException:画布:尝试使用回收的位图android.graphics.Bitmap @ 4070dab0尝试回收时。

另外,当我没有进行回收时,除了看到图像仍然闪烁外,其他所有操作都有效。 甚至有时会显示错误的图像。

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

    if (imageView != null && urlString != null && urlString.length() > 0)
    {
        imageView.setTag(urlString);

        final Handler handler = new Handler() {
            @Override
            public void handleMessage(Message message) {
                Drawable d = imageView.getDrawable();
                if(d != null){
                     ((BitmapDrawable)imageView.getDrawable()).getBitmap().recycle();
                     imageView.setImageBitmap(null);
                }

                imageView.setImageDrawable((Drawable) message.obj);
            }
        };

        Thread thread = new Thread() {
            @Override
            public void run() {
                if (imageView != null && urlString != null && !urlString.equals(""))
                {
                    URL url;
                    try {
                        if (imageView.getTag().equals(urlString))
                        {
                            InputStream is = fetch(urlString);

                            if (is != null) {
                                Drawable drawable = Drawable.createFromStream((InputStream)is, "src");
                                Message message = handler.obtainMessage(1, drawable);
                                handler.sendMessage(message);
                            } 
                        }
                    }
                    catch (MalformedURLException e) {
                        Log.e(this.getClass().getSimpleName(), "fetchDrawable failed", e);
                    } catch (IOException e) {
                        Log.e(this.getClass().getSimpleName(), "fetchDrawable failed", e);
                    }
                }

            }
        };
        thread.start();
    }

}

private InputStream fetch(String urlString) throws MalformedURLException, IOException {
    if (urlString != null)
    {
        URL url = new URL(urlString);

        URLConnection connection = url.openConnection();
        connection.setUseCaches(true);
        Object response = connection.getContent();
        if (response instanceof InputStream) {
            return (InputStream) response;
        }
    }
    return null;
}

如果您使用的是ListView ,则应该意识到ListView重用了ImageView实例。 如果加载时间太长,并且与之绑定的特定ImageView已重新用于另一个Image,则您的实现将用旧图像覆盖正确的图像。 你需要:

  1. 修改fetchDrawableOnThread方法以将ImageView标记为要获取的URL:通常,您将使用setTag并保存url。
  2. 提取InputStream后,请检查run方法,以确保ImageView中的getTag值与您刚获取的url匹配。 如果它们不匹配,则ListView将重用此ImageView实例,并且您不应该发送Message来显示图像。

在设置新的Drawable之前,您可能还应该在某个地方调用recycle来清理消耗的位图内存,但这是一个更长的故事。

编辑: recycle故事实际上比我记得的要简单(我查了一些旧代码)。 基本上,在更新ImageViewDrawable之前,请检查它是否已经有一个Drawable集,以及是否确实对其调用了recycle 所以像这样:

ImageView iv = getImageView(); // fetch the image view somehow before you set it;
Drawable d = iv.getDrawable();
if(d != null){
     ((BitmapDrawable)iv.getDrawable()).getBitmap().recycle();
     iv.setImageBitmap(null);
}

这将回收以前的Drawable使用的内存,并且应该有助于解决内存耗尽问题。

基于Web视图的异步加载和缓存功能的快速简便的解决方案:

String htmlSnippet = "<html><head/><body>" +
                     "<img height=\"50px\" width=\"50px\" src=\"" + item.getImageUrl() + "\" />" +
                     "</body></html>";
imageWebview.loadData( htmlSnippet, "text/html", "utf-8" );

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM