如何在Android中的ListView中使用延迟加载技术来加载图片

2078

我正在使用ListView来显示一些与图像相关的标题和图像。 我正在从互联网上获取这些图像。 有没有一种方法可以懒加载图像,以便在文本显示时不会阻塞UI,并且图像会随着下载而显示?

图片的总数并不是固定的。


13
你可以使用GreenDroid的AsyncImageView。只需调用 setUrl 即可。 - Pascal Dimassimo
8
我已经使用过它了,它是一个很棒的实现。坏消息是,AsyncImageView是大型GreenDroid项目的一部分,即使你只需要AsyncImageView,这也会使你的应用程序变得更大。此外,GreenDroid项目似乎自2011年以来就没有更新了。 - borisstr
6
你甚至可以试试这个库:Android-http-image-manager,我认为它是最适合异步加载图片的。 - Ritesh Kumar Dubey
36
只需使用 Picasso,它会自动完成所有操作。'Picasso.with(yourContext).load(img src/path/drawable here).into(imageView i.e your target);'就这样! - Anuj Sharma
10
尝试使用这个库:https://github.com/nostra13/Android-Universal-Image-Loader,它非常适用于图片的懒加载和缓存,速度快且高效。 - krunal patel
2
使用Glide图像加载库。 - Devendra Kulkarni
41个回答

46

我处理它的方式是启动一个线程在后台下载图像,并为每个列表项分配一个回调函数。当一张图片下载完成时,它会调用回调函数,更新列表项的视图。

然而,当您正在回收视图时,这种方法并不太有效。


我也使用为每个图像使用一个线程的方法。如果将模型与视图分离,您可以将模型持久化到Activity之外(例如在“应用程序”类中),以便将它们缓存。请注意,如果您有许多图像,则可能会耗尽资源。 - James A Wilson
你能否详细说明一下?我是 Android 开发的新手。不过还是谢谢你的建议。 - lostInTransit
14
为每张图片启动一个新线程并不是一个有效的解决方案。这样会导致内存中出现大量线程,并且会冻结用户界面。 - Fedor
Fedor,同意,我通常使用队列和线程池,这是我认为最好的方法。 - jasonhudgins

36

我只想再补充一个很好的例子——XML Adapters。由于谷歌在使用它,我也使用了相同的逻辑来避免OutOfMemory错误。

基本上,这个ImageDownloader就是你的答案(因为它满足你大部分的需求)。你还可以在其中实现其他一些功能。


3
ImageDownloader类未被编译:请查看下面的解决方案 http://code.google.com/p/parleys-android-nextgen/issues/detail?id=1 - Sam

33

这是在Android上常见的问题,已经有许多人用许多方法解决了。在我看来,最好的解决方案是一个相对较新的库,叫作Picasso。以下是其要点:

  • 开源,由ActionBarSherlock名声显赫的Jake Wharton领导。
  • 用一行代码异步从网络或应用程序资源中加载图像
  • 自动检测ListView
  • 自动磁盘和内存缓存
  • 可以进行自定义转换
  • 有许多可配置选项
  • 超级简单的API
  • 经常更新

33

2
我认为这是最好的解决方案 - 其他答案都非常老 - Volley非常快,结合Jake Warthon的DiskLruCache是一个完美的解决方案 - 我尝试了很多其他的解决方案,但没有一个像Volley那样稳定和快速。 - Alexander Sidikov Pfeif

29

好的,从互联网加载图像有很多解决方案。您也可以使用库Android-Query。它会给您所有所需的活动。确保您想要做什么,并阅读库维基页面。并解决图像加载限制。

这是我的代码:

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    View v = convertView;
    if (v == null) {
        LayoutInflater vi = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        v = vi.inflate(R.layout.row, null);
    }

    ImageView imageview = (ImageView) v.findViewById(R.id.icon);
    AQuery aq = new AQuery(convertView);

    String imageUrl = "http://www.vikispot.com/z/images/vikispot/android-w.png";

    aq.id(imageview).progress(this).image(imageUrl, true, true, 0, 0, new BitmapAjaxCallback() {
        @Override
        public void callback(String url, ImageView iv, Bitmap bm, AjaxStatus status) {
            iv.setImageBitmap(bm);
        }
    ));

    return v;
}

这应该能解决你的懒加载问题。


干得好,但需要一个JAR文件来包含在你的项目中。你可以从这里下载那个JAR文件。AQuery androidAQuery = new AQuery(this); 链接是:https://code.google.com/archive/p/android-query/downloads - Selim Raza

27

我认为这个问题在Android开发者中非常流行,有很多库声称可以解决这个问题,但只有少数几个似乎达标。 AQuery是其中之一,但它在所有方面都比大多数库更好,并且值得尝试。


23

你必须尝试这个最佳的通用加载器。在懒加载方面,我已经进行了许多研究后使用了这个。

通用图像加载器

功能

  • 多线程图像加载(异步或同步)
  • 对ImageLoader的配置进行广泛定制(线程执行器、下载器、解码器、内存和磁盘缓存、显示图像选项等)
  • 每个显示图像调用的许多自定义选项(存根图像、缓存开关、解码选项、位图处理和显示等)
  • 在内存和/或磁盘中缓存图像(设备文件系统或SD卡)
  • 监听加载过程(包括下载进度)

支持Android 2.0+

enter image description here


22

看一下 Shutterbug,这是Applidium开发的轻量级SDWebImage(iOS上的一款不错的库)在Android上的移植版。

它支持异步缓存、存储失败的URL、良好处理并发,并包括有用的子类。

欢迎提交拉取请求(和错误报告)!


18

DroidParts拥有ImageFetcher,它无需任何配置即可开始使用。

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

克隆DroidPartsGram以获得示例:

Enter image description here


嗨,我已经查看了代码示例,但是在使用ImageFetcher和ArrayAdapter时遇到了问题,您介意看一下我的问题吗?http://stackoverflow.com/questions/21089147/recycling-issues-in-arrayadapter-using-imagefetcher 谢谢 =] - masha

17

Novoda还有一个很棒的延迟加载图片库,像Songkick、Podio、SecretDJ和ImageSearch等许多应用程序都使用他们的库。

他们的库托管在Github上,这里,并且他们也有一个非常活跃的问题跟踪器。他们的项目似乎也很活跃,在撰写本回答时已经有300多次提交。


2
其实Novoda是一个很棒的库,但是有时候你并不需要一个庞大的库,只需要一个简单的解决方案。这就是为什么Github上的LazyList如此出色,如果你的应用程序只在listView中显示一张图片,并且不是应用程序的主要功能,只是另一个活动,我更愿意使用一些轻量级的东西。否则,如果你知道你经常需要使用它并且是核心的一部分,请尝试使用Novoda。 - Nicolas Jafelle

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接