在做这个问题之前,我搜索并阅读了这些: Lazy load of images in ListView Android - Issue with lazy loading images into a ListView
我的问题是我有一个 ListView
,其中:
- 每一行包含一个
ImageView
,其 内容将从 互联网 - 每一行的 View 都被回收 ApiDemo 的 List14
我最终想要的是:
- 延迟加载图像,仅当用户 滚动到他们
- 在不同线程上加载图像以 保持响应能力
我目前的做法:
- 在适配器的
getView()
方法中,除了 设置其他 subview ,我启动一个 从中加载位图的新线程 互联网。当加载线程 完成后,它返回要在ImageView
上设置的Bitmap
(我使用AsyncTask
或Handler
执行此操作)。 - 因为我回收了
ImageView
,它可能 是我首先要设置的情况 一个带有Bitmap#1
的 View ,稍后需要 将其设置为Bitmap#2
当用户 向下滚动。Bitmap#1
可能会发生 加载时间比Bitmap#2
长,所以 它可能最终会覆盖Bitmap#2
风景。我通过维护来解决这个问题 一个WeakHashMap
可以记住我想要的最后一个Bitmap
为该 View 设置。
下面是我当前方法的伪代码。我省略了缓存等其他细节,只是为了清楚起见。
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 被销毁怎么办?
- 加载时是否有任何风险 线程回调到 ImageView 稍后,当 Activity 已经 毁了?
- 此外,
AsyncTask
有一些全局的 下面的线程池,所以如果冗长 任务不会被取消 不再需要了,我可能会结束 浪费时间加载用户
没看见。我目前的设计 把这个东西放全局也太 丑陋,并可能最终导致一些 超出我的范围的泄漏 理解。而不是制作ImageLoader
像这样的单例, 我正在考虑实际创建 单独的ImageLoader
对象 不同的Activities
,那么当一个Activity
被销毁,它的所有AsyncTask
将被取消。这是 太尴尬了?
无论如何,我想知道在 Android 中是否有安全和标准的方法来执行此操作。另外,我不了解 iPhone,但那里有类似的问题吗?他们有执行此类任务的标准方法吗?
非常感谢。
最佳答案
I solve this by maintaining a WeakHashMap that remembers the last Bitmap I want to set for that view.
我采用了通过 setTag()
将所需图像的 URL 附加到 ImageView
上的方法。然后,当我下载图像时,我仔细检查 ImageView
URL——如果它与我刚刚下载的不同,我不会更新 ImageView
,因为它被回收了。我只是缓存它。
Is there any risk when the loading thread calls back to the ImageView later, when the Activity is already destroyed?
我不知道有任何风险,除了会浪费一些 CPU 时间和带宽(以及电池)。
Instead of making ImageLoader a singleton like this, I'm thinking of actually creating separate ImageLoader objects for different Activities, then when an Activity gets destroyed, all its AsyncTask will be canceled. Is this too awkward?
如果 AsyncTask
已经在运行,取消它并不是一件容易的事。我只是让它运行完成。
理想情况下,避免单例。使用 Service
,或通过 onRetainNonConfigurationInstance()
将您的 ImageLoader
传递给您的 Activity 的下一个实例(例如,isFinishing()
在onDestroy()
中为false
,所以这是一个轮换。
关于android - 在不同线程上的 ListView 中加载图像的安全、标准方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2888713/