java Android - 将图像延迟加载到 ListView 的问题
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1409623/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Android - Issue with lazy loading images into a ListView
提问by Tom van Zummeren
This is a very common scenario: displaying images in a ListView which have to be downloaded from the internet.
这是一个非常常见的场景:在 ListView 中显示必须从 Internet 下载的图像。
Right now I have a custom subclass of ArrayAdapter which I use for the ListView. In my getView() implementation of the ArrayAdapter, I spawn a separate thread to load an image. After the loading is done, it looks up the appropriate ImageView and sets the image with ImageView.setImageDrawable(). So the solution I used is kind of similar to this one: Lazy load of images in ListView
现在我有一个用于 ListView 的 ArrayAdapter 的自定义子类。在 ArrayAdapter 的 getView() 实现中,我生成了一个单独的线程来加载图像。加载完成后,它会查找相应的 ImageView 并使用 ImageView.setImageDrawable() 设置图像。所以我使用的解决方案有点类似于这个:ListView 中的图像延迟加载
The problem I'm having is that as soon as I make the call to setImageDrawable() on the ImageView, the ListView somehow refreshes all currently visible rows in the list! This results in kind of an infinite loop:
我遇到的问题是,一旦我在 ImageView 上调用 setImageDrawable(),ListView 就会以某种方式刷新列表中所有当前可见的行!这导致了一种无限循环:
- getView() is called
- thread is spawned to load image
- image is loaded; setImageDrawable() is called on ImageView
- ListView picks it up for some reason and refreshes itself
- For the ListView to refresh, getView() is called for each visible row, so we go back to step 1 and the whole thing repeats itself
- getView() 被调用
- 生成线程以加载图像
- 图像已加载;在 ImageView 上调用 setImageDrawable()
- ListView 出于某种原因把它捡起来并自我刷新
- 为了让 ListView 刷新,每个可见行都会调用 getView(),所以我们回到第 1 步,整个过程会重复
So as far as I can see, the solution proposed in "Android - How do I do a lazy load of images in ListView" (see link above) simply doesn't work. It might look like it does, but it will run very slow because in the background, it keeps reloading the currently visible rows.
因此,据我所知,“Android - 如何在 ListView 中延迟加载图像”(参见上面的链接)中提出的解决方案根本不起作用。它可能看起来确实如此,但运行速度会非常慢,因为在后台,它会不断重新加载当前可见的行。
Did anyone encounter this before and/or have a solution for this?
有没有人遇到过这个问题和/或有解决方案?
采纳答案by Will
In the linked solution, fetchDrawableOnThread()should only be called if the view does not already have the correct drawable.
在链接的解决方案中,fetchDrawableOnThread()只有在视图还没有正确的可绘制对象时才应调用。
A view does not have a drawable if getDrawable()returns null.
如果getDrawable()返回 null,则视图没有可绘制对象。
If you are reusing slots, you views you need to go further and manage the state. If your views have a member variable storing the URL, and a boolean to say whether it is loaded, it'd be easy to know whether to call fetchDrawableOnThread()or not, for example.
如果您正在重用插槽,则您认为需要进一步管理状态。例如,如果您的视图有一个存储 URL 的成员变量和一个表示它是否已加载的布尔值,则很容易知道是否调用fetchDrawableOnThread()。
I'd speculate that the drawable's toString()detailed the path from which the image was loaded. (If it doesn't, you could subclass the drawable returned to make it so). In this case, you could avoid the boolean outlined above and just do a comparison to determine if its the right drawable or whether to fetch a replacement.
我推测 drawabletoString()详细说明了加载图像的路径。(如果没有,您可以对返回的可绘制对象进行子类化以使其如此)。在这种情况下,您可以避免使用上面概述的布尔值,只需进行比较以确定它是否是正确的可绘制对象或是否获取替换。
Additionally, your getView() on a visible row should ensure that those that no longer visible get unloaded, to prevent memory exhaustion. A finesse would be to move the no longer visible images to soft references (so they are unloaded when memory is needed) as another poster on the original thread noted.
此外,可见行上的 getView() 应确保那些不再可见的被卸载,以防止内存耗尽。一个技巧是将不再可见的图像移动到软引用(以便在需要内存时卸载它们),正如原始线程上的另一张海报所指出的那样。
回答by Murat
I used the code in following link : another stackoverflow question
我使用了以下链接中的代码:another stackoverflow question
i made small changes in order to solve recycling view problem.i set the url of image to Tag of imageview in the adapter. Following code contains my solution that solves recycling problem:
为了解决回收视图问题,我做了一些小改动。我在适配器中将图像的 url 设置为图像视图的标签。以下代码包含我解决回收问题的解决方案:
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;
}
回答by saberrider
I had the same issue.
我遇到过同样的问题。
After almost 2 days of heavy debugging/optimizing and trying to figure out, why my getView()is called for all views over and over again when using setImageBitmap()in a Row, I came up with a dirty solution:
经过近 2 天的大量调试/优化并试图弄清楚为什么我在 Row 中getView()使用时一遍又一遍地调用所有视图setImageBitmap(),我想出了一个肮脏的解决方案:
1) Extend a custom ImageViewwhich you use for all the Images in your List
1)扩展ImageView您用于列表中所有图像的自定义
2) in this ImageViewoverwrite the method
2)在这个ImageView覆盖方法
@Override
public void requestLayout()
{
return;
}
3) Dirty, but for me it works
3)脏,但对我来说它有效
4) Profit ;)
4) 利润 ;)
回答by CommonsWare
I have a ThumbnailAdapterthat wraps up this whole pattern that may help.
我有一个ThumbnailAdapter,它包含了可能有帮助的整个模式。

