在提出这个问题之前,我已经搜索并阅读了这些问题: 在 ListView Android 中延迟加载图像 - 将图像延迟加载到 ListView 中的问题
我的问题是我有一个ListView
,其中:
- 每行包含一个
ImageView
,其内容将从互联网加载 - 每一行的视图都像 ApiDemo 的 List14 一样被回收
我最终想要的:
- 延迟加载图像,仅当用户滚动到它们时
- 在不同的线程上加载图像以保持响应能力
我目前的做法:
- 在适配器的
getView()
方法中,除了设置其他子视图之外,我还启动了一个从 Internet 加载位图的新线程。当该加载线程完成时,它会返回Bitmap
要设置的ImageView
(我使用AsyncTask
or来执行此操作Handler
)。 - 因为我recycle
ImageView
s,所以可能是我先想用 设置一个视图Bitmap#1
,然后想Bitmap#2
在用户向下滚动的时候设置它。Bitmap#1
可能碰巧需要比Bitmap#2
加载更长的时间,因此它最终可能会覆盖Bitmap#2
视图。我通过维护一个WeakHashMap
记住Bitmap
我想为该视图设置的最后一个来解决这个问题。
下面是我当前方法的一些伪代码。我省略了缓存等其他细节,只是为了保持清楚。
public class ImageLoader {
// keeps track of the last Bitmap we want to set for this ImageView
private static final WeakHashMap<ImageView, AsyncTask> assignments
= new WeakHashMap<ImageView, AsyncTask>();
/** Asynchronously sets an ImageView to some Bitmap loaded from the internet */
public static void setImageAsync(final ImageView imageView, final String imageUrl) {
// cancel whatever previous task
AsyncTask oldTask = assignments.get(imageView);
if (oldTask != null) {
oldTask.cancel(true);
}
// prepare to launch a new task to load this new image
AsyncTask<String, Integer, Bitmap> newTask = new AsyncTask<String, Integer, Bitmap>() {
protected void onPreExecute() {
// set ImageView to some "loading..." image
}
protected Bitmap doInBackground(String... urls) {
return loadFromInternet(imageUrl);
}
protected void onPostExecute(Bitmap bitmap) {
// set Bitmap if successfully loaded, or an "error" image
if (bitmap != null) {
imageView.setImageBitmap(bitmap);
} else {
imageView.setImageResource(R.drawable.error);
}
}
};
newTask.execute();
// mark this as the latest Bitmap we want to set for this ImageView
assignments.put(imageView, newTask);
}
/** returns (Bitmap on success | null on error) */
private Bitmap loadFromInternet(String imageUrl) {}
}
我仍然遇到的问题:如果 Activity 在某些图像仍在加载时被破坏怎么办?
- 当 Activity 已经销毁时,加载线程稍后回调 ImageView 是否有任何风险?
- 此外,
AsyncTask
它下面有一些全局线程池,所以如果不再需要冗长的任务时没有取消它们,我最终可能会浪费时间加载用户
看不到的东西。我目前在全球范围内保留这个东西的设计太丑陋了,最终可能会导致一些我无法理解的泄漏。ImageLoader
我没有像这样制作 单例,而是考虑实际ImageLoader
为 different 创建单独的对象Activities
,然后当 anActivity
被销毁时,它的所有 内容都AsyncTask
将被取消。这也太尴尬了吧?
无论如何,我想知道在 Android 中是否有一种安全且标准的方法来执行此操作。另外,我不了解 iPhone,但那里有类似的问题吗?他们有标准的方法来完成这种任务吗?
非常感谢。