我正在使用ListView来显示与这些图像相关的一些图像和标题。我正在从互联网上获取图像。是否有一种方法可以延迟加载图像,以便在文本显示时,UI不会被阻止,图像在下载时显示?

图像总数不是固定的。


当前回答

我一直在使用新的Android Volley Library com.Android.Volley.toolbox.NetworkImageView中的NetworkImageView,它似乎工作得很好。显然,这是Google Play和其他新的Google应用程序中使用的相同视图。绝对值得一看。

Google I/O 2013凌空图像缓存教程开发者Google活动

其他回答

更新:请注意,这个答案现在非常无效。垃圾回收器对SoftReference和WeakReference进行攻击,因此此代码不适用于新应用。(相反,请尝试其他答案中建议的通用图像加载器之类的库。)

感谢James提供的代码,感谢鲍龙提供的使用SoftReference的建议。我在James的代码上实现了SoftReference更改。不幸的是,SoftReferences导致我的图像被垃圾收集得太快。在我的情况下,没有SoftReference的东西很好,因为我的列表大小有限,图像也很小。

一年前有一场关于谷歌群组上SoftReferences的讨论:链接到线程。作为过早垃圾收集的解决方案,他们建议使用dalvik.system.VMRuntime.setMinimumHeapSize()手动设置VM堆大小,这对我来说不是很有吸引力。

public DrawableManager() {
    drawableMap = new HashMap<String, SoftReference<Drawable>>();
}

public Drawable fetchDrawable(String urlString) {
    SoftReference<Drawable> drawableRef = drawableMap.get(urlString);
    if (drawableRef != null) {
        Drawable drawable = drawableRef.get();
        if (drawable != null)
            return drawable;
        // Reference has expired so remove the key from drawableMap
        drawableMap.remove(urlString);
    }

    if (Constants.LOGGING) Log.d(this.getClass().getSimpleName(), "image url:" + urlString);
    try {
        InputStream is = fetch(urlString);
        Drawable drawable = Drawable.createFromStream(is, "src");
        drawableRef = new SoftReference<Drawable>(drawable);
        drawableMap.put(urlString, drawableRef);
        if (Constants.LOGGING) Log.d(this.getClass().getSimpleName(), "got a thumbnail drawable: " + drawable.getBounds() + ", "
                + drawable.getIntrinsicHeight() + "," + drawable.getIntrinsicWidth() + ", "
                + drawable.getMinimumHeight() + "," + drawable.getMinimumWidth());
        return drawableRef.get();
    } catch (MalformedURLException e) {
        if (Constants.LOGGING) Log.e(this.getClass().getSimpleName(), "fetchDrawable failed", e);
        return null;
    } catch (IOException e) {
        if (Constants.LOGGING) Log.e(this.getClass().getSimpleName(), "fetchDrawable failed", e);
        return null;
    }
}

public void fetchDrawableOnThread(final String urlString, final ImageView imageView) {
    SoftReference<Drawable> drawableRef = drawableMap.get(urlString);
    if (drawableRef != null) {
        Drawable drawable = drawableRef.get();
        if (drawable != null) {
            imageView.setImageDrawable(drawableRef.get());
            return;
        }
        // Reference has expired so remove the key from drawableMap
        drawableMap.remove(urlString);
    }

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

    Thread thread = new Thread() {
        @Override
        public void run() {
            //TODO : set imageView to a "pending" image
            Drawable drawable = fetchDrawable(urlString);
            Message message = handler.obtainMessage(1, drawable);
            handler.sendMessage(message);
        }
    };
    thread.start();
}

另一种方法是通过getView()方法中线程中的适配器:

Thread pics_thread = new Thread(new Runnable() {
    @Override
    public void run() {
        Bitmap bitmap = getPicture(url);
        if(bitmap != null) {
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    holder.imageview.setImageBitmap(bitmap);            
                    adapter.notifyDataSetChanged();
                }                       
            });             
        }       
    }                       
});

pics_thread.start();

当然,您应该始终缓存图像以避免额外的操作,您可以将图像放在HashMap数组中,检查图像是否存在于数组中,如果不存在,则继续执行线程或从HashMap数组加载图像。此外,请始终检查内存是否泄漏,位图和可绘制文件通常占用大量内存。优化代码取决于您。

您可以尝试使用Aquery Android库来延迟加载图像和列表视图。。。以下代码可能会帮助您。。。。。从这里下载库。

AQuery aq = new AQuery(mContext);
aq.id(R.id.image1).image("http://data.whicdn.com/images/63995806/original.jpg");

DroidParts的ImageFetcher需要零配置才能启动。

使用磁盘和内存中最近最少使用(LRU)缓存。高效解码图像。支持在后台线程中修改位图。具有简单的交叉褪色。具有图像加载进度回调。

例如,克隆DroidPartsGram:

毕加索

使用杰克·沃顿的毕加索图书馆。(ActionBarSherlock开发人员提供的完美图像加载库)

一个强大的Android图像下载和缓存库。

图像为Android应用程序添加了急需的上下文和视觉效果。Picasso允许在应用程序中轻松加载图像,通常只需一行代码!

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("your-url-here").into(imageView);

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

Glide图像加载库

Facebook上的壁画

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

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

壁画Github

在Android4.x及更低版本中,Fresco将图像放在Android内存的一个特殊区域。这让您的应用程序运行得更快,并且更少发生可怕的OutOfMemoryError。

壁画文献