AsynTask

2015-10-13  本文已影响189人  Tyler

因为要同一个实例执行多次很麻烦,没必要。

假设允许多次 execute 同一个 AsyncTask 多次,也就是说队列中会有同一个 AsyncTask 实例出现多次。首先 AsyncTask 需要改动很多,比如把各种状态额外保存多份,不能像现在这样简单做为 AsyncTask 的成员变量,这些先不说,从调用者角度来看:

你继承 AsyncTask 实现了自己的一个子类 MyTask,加了一些成员变量,你想多次执行同一个 MyTask,发现不对啊,我第一次执行后这些成员变量的值都变了,状态不对。还得加个 reset 函数把这些值改回初使值,再一想何必呢,我干脆重新 new 一个 MyTask 不是更简单有效吗。

另外,虽然用默认的 Executor 是不会同时运行的,但你 execute 时如果用了自己定义 Executor,是有可能会多线程同时访问的。这时你也会想还要搞线程同步太麻烦了还是我还是 new 两个 MyTask 别想着同一个 MyTask 运行两次好了。

所以,你看,就算人家允许你同一个 AsyncTask execute 多次,你既然也不会用这功能的话,我就干脆不许你 execute 两次好了。

最主要的是在 Activity 销毁时就应该把所有属于这个 Activity 的 Task cancel 掉。

你的 Task 应该在 onCancelled 函数中做相应的处理。比如说如果 Task 是用 来联网的,就应该在 onCancelled 中 disconnect。然后在 onCancelled 中将指向 Activity 的引用设为 null;

弱引用更多的是一份保险,保证如果你在没有正确 cancel Task 时,不会让本应去死的 Activity 还因为 Task 的引用还在内存中晃悠。当然这个保险是很有必要的。

弱引用Demo:

static class AsyncDrawable extends BitmapDrawable {
    private final WeakReference<BitmapWorkerTask> bitmapWorkerTaskReference;

    public AsyncDrawable(Resources res, Bitmap bitmap,
            BitmapWorkerTask bitmapWorkerTask) {
        super(res, bitmap);
        bitmapWorkerTaskReference =
            new WeakReference<BitmapWorkerTask>(bitmapWorkerTask);
    }

    public BitmapWorkerTask getBitmapWorkerTask() {
        return bitmapWorkerTaskReference.get();
    }
}
public void loadBitmap(int resId, ImageView imageView) {
    if (cancelPotentialWork(resId, imageView)) {
        final BitmapWorkerTask task = new BitmapWorkerTask(imageView);
        final AsyncDrawable asyncDrawable =
                new AsyncDrawable(getResources(), mPlaceHolderBitmap, task);
        imageView.setImageDrawable(asyncDrawable);
        task.execute(resId);
    }
}

public static boolean cancelPotentialWork(int data, ImageView imageView) {
    final BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(imageView);

    if (bitmapWorkerTask != null) {
        final int bitmapData = bitmapWorkerTask.data;
        // If bitmapData is not yet set or it differs from the new data
        if (bitmapData == 0 || bitmapData != data) {
            // Cancel previous task
            bitmapWorkerTask.cancel(true);
        } else {
            // The same work is already in progress
            return false;
        }
    }
    // No task associated with the ImageView, or an existing task was cancelled
    return true;
}

private static BitmapWorkerTask getBitmapWorkerTask(ImageView imageView) {
   if (imageView != null) {
       final Drawable drawable = imageView.getDrawable();
       if (drawable instanceof AsyncDrawable) {
           final AsyncDrawable asyncDrawable = (AsyncDrawable) drawable;
           return asyncDrawable.getBitmapWorkerTask();
       }
    }
    return null;
}

class BitmapWorkerTask extends AsyncTask<Integer, Void, Bitmap> {
    ...

    @Override
    protected void onPostExecute(Bitmap bitmap) {
        if (isCancelled()) {
            bitmap = null;
        }

        if (imageViewReference != null && bitmap != null) {
            final ImageView imageView = imageViewReference.get();
            final BitmapWorkerTask bitmapWorkerTask =
                    getBitmapWorkerTask(imageView);
            if (this == bitmapWorkerTask && imageView != null) {
                imageView.setImageBitmap(bitmap);
            }
        }
    }
}

如果执行了这个 activity 的 view 的操作的话,会报异常。因为此时这个 view 已经不属于任何活的Window。

最多就是 Task 指向 Activity 的引用改成弱引用了。 Task 如果是 Activity 一个成员的话已经泄漏无法访问了。

上一篇 下一篇

猜你喜欢

热点阅读