AsyncTask 坑 (三)AsyncTask对象多次执行

经常看到网上有这种面试题目:一个AsyncTask对象能不能被多次执行?

其实,想知道答案,最好的办法就是看文档说明,要是文档说不行那就是不行,行就是行。

如果想知道的更多,那就看代码呗。


AsyncTask的execute函数

excute是用来启动一个异步任务的API,先看看这个函数,

    @MainThread
    public final AsyncTask<Params, Progress, Result> execute(Params... params) {
        return executeOnExecutor(sDefaultExecutor, params);
    }

下面的这个函数里面可以看到有个成员mStatus,代码很简单,如果mStatus不是PENDING,直接丢异常。

    @MainThread
    public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
            Params... params) {
        if (mStatus != Status.PENDING) {
            switch (mStatus) {
                case RUNNING:
                    throw new IllegalStateException("Cannot execute task:"
                            + " the task is already running.");
                case FINISHED:
                    throw new IllegalStateException("Cannot execute task:"
                            + " the task has already been executed "
                            + "(a task can be executed only once)");
            }
        }

        mStatus = Status.RUNNING;

        onPreExecute();

        mWorker.mParams = params;
        exec.execute(mFuture);

        return this;
    }

看看状态枚举,很简单就只有3种状态,PENDING, RUNNING, FINISHED。

   public enum Status {
        /**
         * Indicates that the task has not been executed yet.
         */
        PENDING,
        /**
         * Indicates that the task is running.
         */
        RUNNING,
        /**
         * Indicates that {@link AsyncTask#onPostExecute} has finished.
         */
        FINISHED,
    }


看mStatus的变化流程:

1. AsyncTask对象创建的时候,初始化成PENDING.

    private volatile Status mStatus = Status.PENDING;

2. execute()里面会判断,如果不是pending(无论是running,还是finished)都直接丢出异常。只有pending才能往下走。当是pending的时候,就直接设置成running。然后就发onPreExecute通知和执行任务。

3. 执行完后,无论成功还是失败,都设置成finished。

    private void finish(Result result) {
        if (isCancelled()) {
            onCancelled(result);
        } else {
            onPostExecute(result);
        }
        mStatus = Status.FINISHED;
    }

从这些代码,其实就可以看出,一个AsyncTask对象被创建出来后,就只能执行一个异步任务。一旦开始执行了,无论在运行过程中,还是运行结束了,都不能在重复执行了。


FutureTask

之前也看到过,AsyncTask的构造函数里面,会创建一个mWorker和mFuture。mWorker会传给mFuture,mFuture里面的成员callable就是引用了mWorker对象。

然后FutureTask一次执行完后,就会调用下面的函数,很清楚callable被赋值为null了。

    private void finishCompletion() {
        // assert state > COMPLETING;
        for (WaitNode q; (q = waiters) != null;) {
            if (U.compareAndSwapObject(this, WAITERS, q, null)) {
                for (;;) {
                    Thread t = q.thread;
                    if (t != null) {
                        q.thread = null;
                        LockSupport.unpark(t);
                    }
                    WaitNode next = q.next;
                    if (next == null)
                        break;
                    q.next = null; // unlink to help gc
                    q = next;
                }
                break;
            }
        }

        done();

        callable = null;        // to reduce footprint
    }

而mFuture和mWorker都是被声明称final的

    private final WorkerRunnable<Params, Result> mWorker;
    private final FutureTask<Result> mFuture;

那么当一个AsyncTask对象被创建出来后,mFuture和mWorker只能被初始化一次,而mFuture执行完一次任务后,就会调用finishCompletion,然后把callable赋值成0,也就是说就算后面再执行mFuture,因为callable被清0了,任务也不会再次执行。

从种种迹象表明,一个AsyncTask对象只能执行一次任务,是google刻意限制的。

至于为什么要设计成这样?

我想Google设计AsyncTask的初衷就是:这是个轻量级的类,用于执行简单的后台操作。

一个任务就是一个AsyncTask对象,如果想执行其他任务或者同个任务再执行一次,那就再创建一个AsyncTask对象呗。





猜你喜欢

转载自blog.csdn.net/zj510/article/details/51531353