图片加载AsyncTask并发问题

在列表控件中使用AsycnTask加载图片时,会带来并发问题。

如果每个子视图都触发一个AsyncTask,因为AsyncTask内部是一个线程池,并发触发时,不能确保每个子视图的AsyncTask都进入了队列,而且异步任务的完成顺序和启动顺序也不一定一致。

Multithreading For Performance这篇文章提供了一种方法。

主要方案如下:

  1. 通过定制一个BitmapDrawable,让ImageView储存当前AsyncTask的引用(弱引用)

    BitmapLoadTask,一个加载图片的AsyncTask,可以执行从网络、文件加载图片

class AsyncDrawable extends BitmapDrawable {
    private final WeakReference downloadTaskWeakReference;
    
    AsyncDrawable(BitmapLoadTask downloadTask) {
        this.downloadTaskWeakReference = new WeakReference<>(downloadTask);
    }
    public DownloadTask getDownloadTask() {
        return downloadTaskWeakReference.get();
    }
}
  1. ListView显示一个ImageView,并开始下载之前,判断是否有另一个AsyncTask已经与该ImageView绑定

    1. 如果存在一个Task,并且它的任务就是当前ImageView的任务,则不会新建一个AsyncTask去下载
    2. 如果不存在,或者存在的任务执行的下载不同于当前的任务,就取消当期的Task,然后新建一个。

    下载时判断:
    java public void loadBitmap(String url, ImageView imageView) { if (shouldNewTaskToLoad(url, imageView)) { final BitmapLoadTask bitmapLoadTask = new BitmapLoadTask(imageView); final AsyncDrawable asyncDrawable = new AsyncDrawable(bitmapLoadTask); imageView.setImageDrawable(asyncDrawable); bitmapLoadTask.execute(url); } }java

    判断的逻辑:

    public static boolean shouldNewTaskToLoad(String url, ImageView imageView) {
         if (imageView != null) {
             AsyncDrawable asyncDrawable = (AsyncDrawable) imageView.getDrawable();
             if (asyncDrawable != null) {
                 BitmapLoadTask bitmapLoadTask = asyncDrawable.getDownloadTask();
                 if (bitmapLoadTask != null) {
                     //如果当前要下载的图片的地址与ImageView中储存的Task下载的地址不想等
                     if (url == null || (!url.equals(bitmapLoadTask.url))) {
                         bitmapLoadTask.cancel(true);
                     } else {
                         return false;
                     }
                 }
             }
         }
         return true;
     }
  2. 使用:在加载图片时:使用setImageDrawable将AsyncTask与ImageView关联

    if (shouldNewTaskToLoad(url, imageView)) {
       final BitmapLoadTask bitmapLoadTask = new BitmapLoadTask(imageView);
       final AsyncDrawable asyncDrawable = new AsyncDrawable(bitmapLoadTask);
       imageView.setImageDrawable(asyncDrawable);
       bitmapLoadTask.execute(url);
        }

你可能感兴趣的:(图片加载AsyncTask并发问题)