android - 在不同线程上的 ListView 中加载图像的安全、标准方法?

标签 android listview multithreading imageview android-asynctask

在做这个问题之前,我搜索并阅读了这些: Lazy load of images in ListView Android - Issue with lazy loading images into a ListView

我的问题是我有一个 ListView,其中:

  • 每一行包含一个 ImageView,其 内容将从 互联网
  • 每一行的 View 都被回收 ApiDemo 的 List14

我最终想要的是:

  • 延迟加载图像,仅当用户 滚动到他们
  • 在不同线程上加载图像以 保持响应能力

我目前的做法:

  • 在适配器的 getView() 方法中,除了 设置其他 subview ,我启动一个 从中加载位图的新线程 互联网。当加载线程 完成后,它返回要在 ImageView 上设置的 Bitmap(我使用 AsyncTaskHandler 执行此操作)。
  • 因为我回收了 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/

相关文章:

winforms - 有没有办法为ListView制作一个加载栏(进度条)?

c - 多次调用 pthread_join 如何工作?

android google 登录和 facebook 登录按钮看起来完全不同

android - 如何在 Android 上以 ListView 显示文件

使用 H2 的 Android 示例

android - 通过单击 ListView 项目发送字符串

multithreading - 线程执行结果

c++ - 如何将数据写入缓冲区并使用第二个线程将缓冲区写入二进制文件?

android - java.lang.illegalstateexception : a factory has already been set on this layoutinflater 异常

android - 解析推送第一次加载通知图标失败