AsyncTask源碼分析

AsyncTask是Android提供的一個異步加載任務的工具類,AsyncTask源碼其實不是特別複雜,不過由於在Android3.0後進行了修改,導致AsyncTask的使用還是很容易入坑的。

public final AsyncTask<Params, Progress, Result> execute(Params... params) {
        return executeOnExecutor(sDefaultExecutor, params);
    }
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;
    }

AsyncTask默認的execute方法會調用executeOnExecutor,傳入sDefaultExecutor。

private static class SerialExecutor implements Executor {
        final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
        Runnable mActive;

        public synchronized void execute(final Runnable r) {
            mTasks.offer(new Runnable() {
                public void run() {
                    try {
                        r.run();
                    } finally {
                        scheduleNext();
                    }
                }
            });
            if (mActive == null) {
                scheduleNext();
            }
        }

        protected synchronized void scheduleNext() {
            if ((mActive = mTasks.poll()) != null) {
                THREAD_POOL_EXECUTOR.execute(mActive);
            }
        }
    }
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;

默認的SERIAL_EXECUTOR是用來對任務進行排隊的,真正的執行在scheduleNext()中。

protected synchronized void scheduleNext() {
            if ((mActive = mTasks.poll()) != null) {
                THREAD_POOL_EXECUTOR.execute(mActive);
            }
        }

可以看到THREAD_POOL_EXECUTOR纔是真正用來執行任務的線程池。之所以這麼做,是Google在3.0之後讓AsyncTask的任務串行化來避免一些並行錯誤。不過想要並行也是可以的,調用executeOnExecutor(Executor exec,Params... params),傳入自己配置的線程池來執行併發任務。

    private static final int CORE_POOL_SIZE = 5;
    private static final int MAXIMUM_POOL_SIZE = 128;
    private static final int KEEP_ALIVE = 1;

    private static final ThreadFactory sThreadFactory = new ThreadFactory() {
        private final AtomicInteger mCount = new AtomicInteger(1);

        public Thread newThread(Runnable r) {
            return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());
        }
    };

    private static final BlockingQueue<Runnable> sPoolWorkQueue =
            new LinkedBlockingQueue<Runnable>(10);
public static final Executor THREAD_POOL_EXECUTOR
            = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
                    TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);

可以看到THREAD_POOL_EXECUTOR是public的,因此也可以選擇THREAD_POOL_EXECUTOR來執行併發。(默認串行執行的情況下實際上這種配置意義就不大了,在3.0之前是不支持串行執行的)

流程分析

先看AsyncTask的構造方法。

public AsyncTask() {
        mWorker = new WorkerRunnable<Params, Result>() {
            public Result call() throws Exception {
                mTaskInvoked.set(true);

                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                return postResult(doInBackground(mParams));
            }
        };

        mFuture = new FutureTask<Result>(mWorker) {
            @Override
            protected void done() {
                try {
                    final Result result = get();

                    postResultIfNotInvoked(result);
                } catch (InterruptedException e) {
                    android.util.Log.w(LOG_TAG, e);
                } catch (ExecutionException e) {
                    throw new RuntimeException("An error occured while executing doInBackground()",
                            e.getCause());
                } catch (CancellationException e) {
                    postResultIfNotInvoked(null);
                } catch (Throwable t) {
                    throw new RuntimeException("An error occured while executing "
                            + "doInBackground()", t);
                }
            }
        };
    }

AsyncTask在構造方法中創建了WorkerRunnable和FutureTask,WorkerRunnable是實現了Callable的類,內部保存Params。

private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
        Params[] mParams;
    }

因此AsyncTask是採用FutureTask來進行異步計算的。FutureTask是一個可以返回異步結果、取消操作等的Future接口的實現,同時FutureTask又實現了Runnable,因此也直接在線程中運行。

在WorkerRunnable的call方法中最後會執行postResult(doInBackground(mParams));,可以看到doInBackground確實是在子線程執行的。

private Result postResult(Result result) {
        Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT,
                new AsyncTaskResult<Result>(this, result));
        message.sendToTarget();
        return result;
    }

postResult將計算結果封裝成AsyncTaskResult發給sHandler。

private static final InternalHandler sHandler = new InternalHandler();
private static class InternalHandler extends Handler {
        @SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})
        @Override
        public void handleMessage(Message msg) {
            AsyncTaskResult result = (AsyncTaskResult) msg.obj;
            switch (msg.what) {
                case MESSAGE_POST_RESULT:
                    // There is only one result
                    result.mTask.finish(result.mData[0]);
                    break;
                case MESSAGE_POST_PROGRESS:
                    result.mTask.onProgressUpdate(result.mData);
                    break;
            }
        }
    }
private void finish(Result result) {
        if (isCancelled()) {
            onCancelled(result);
        } else {
            onPostExecute(result);
        }
        mStatus = Status.FINISHED;
    }

sHandler是一個靜態常量,這也說明了爲了切換到主線程第一次AsyncTask必須在主線程創建的原因。InternalHandler在handleMessage的時候會消息類型來判斷是finish還是onProgressUpdate。

斷斷散散的AsyncTask分析就結束了,但是感覺還沒有理清頭緒,現在從execute(Params… params)具體分析一下執行流程。

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

execute調用了executeOnExecutor並傳入了默認的sDefaultExecutor,前面已經說過這是一個用來排隊的線程池。

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;
    }

executeOnExecutor一進來會判斷mStatus的狀態(mStatus初始化爲PENDING狀態)

private volatile Status mStatus = Status.PENDING;

如果mStatus不爲Status.PENDING則會拋出異常,這也是同一個AsyncTask只能執行一次execute的原因。如果是第一執行,首先將mStatus設置爲Status.RUNNING,然後回調onPreExecute();,因此onPreExecute是在任務執行前在主線程回調的。

接着講params設置到mWorker中,然後調用exec.execute(mFuture);,我們來看一下exec,也就是SerialExecutor。

private static class SerialExecutor implements Executor {
        final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
        Runnable mActive;

        public synchronized void execute(final Runnable r) {
            mTasks.offer(new Runnable() {
                public void run() {
                    try {
                        r.run();
                    } finally {
                        scheduleNext();
                    }
                }
            });
            if (mActive == null) {
                scheduleNext();
            }
        }

        protected synchronized void scheduleNext() {
            if ((mActive = mTasks.poll()) != null) {
                THREAD_POOL_EXECUTOR.execute(mActive);
            }
        }
    }

exec.execute(mFuture); 會將創建一個新的Runnable放到自己的mTasks中。接着判斷mActive是否爲空,第一次進來肯定爲空,接着執行scheduleNext(); 方法。

protected synchronized void scheduleNext() {
            if ((mActive = mTasks.poll()) != null) {
                THREAD_POOL_EXECUTOR.execute(mActive);
            }
        }

scheduleNext方法將SerialExecutor中mTasks的Runnable彈出一個並賦值給mActive(這樣再次調用execute方法就不會進入這個判斷語句中了),然後將Runnable交給真正的線程池THREAD_POOL_EXECUTOR來執行任務。THREAD_POOL_EXECUTOR.execute(mActive)

剛纔也說了第二次調用execute方法不會走到判空語句,就不會執行scheduleNext方法,那怎麼實現串行?現在我們來看SerialExecutor的execute方法。

public synchronized void execute(final Runnable r) {
            mTasks.offer(new Runnable() {
                public void run() {
                    try {
                        r.run();
                    } finally {
                        scheduleNext();
                    }
                }
            });
            if (mActive == null) {
                scheduleNext();
            }
        }

Runnable r 是我們傳進去的mFuture,在mFuture的run()方法執行完後,在try{}finally{scheduleNext();} finally中會執行scheduleNext(),再從mTasks中彈出一個Runnable交給THREAD_POOL_EXECUTOR執行。通過這個邏輯實現了串行執行。

Runnable的run()方法中調用mFuture的run()方法,mFuture的run()方法會調用mWorker的call方法。我們看看mWorker的call做了啥。

mWorker = new WorkerRunnable<Params, Result>() {
            public Result call() throws Exception {
                mTaskInvoked.set(true);

                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                return postResult(doInBackground(mParams));
            }
        };

首先將任務調度標識mTaskInvoked設爲true,表示任務被調用。接着設置進程優先級。最後調用doInBackground(mParams) 執行後臺任務,並通過postResult() 方法將doInBackground返回結果傳到主線程。

private Result postResult(Result result) {
        Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT,
                new AsyncTaskResult<Result>(this, result));
        message.sendToTarget();
        return result;
    }
private static class InternalHandler extends Handler {
        @SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})
        @Override
        public void handleMessage(Message msg) {
            AsyncTaskResult result = (AsyncTaskResult) msg.obj;
            switch (msg.what) {
                case MESSAGE_POST_RESULT:
                    // There is only one result
                    result.mTask.finish(result.mData[0]);
                    break;
                case MESSAGE_POST_PROGRESS:
                    result.mTask.onProgressUpdate(result.mData);
                    break;
            }
        }
    }

InternalHandler判斷傳過來的Message,如果what是MESSAGE_POST_RESULT,代表是doInBackground的返回結果,並調用finish()。如果what是MESSAGE_POST_PROGRESS,代表是開發者調用的publishProgress 來更新進度,並回調onProgressUpdate(Progress… values)。

protected final void publishProgress(Progress... values) {
        if (!isCancelled()) {
            sHandler.obtainMessage(MESSAGE_POST_PROGRESS,
                    new AsyncTaskResult<Progress>(this, values)).sendToTarget();
        }
    }
private void finish(Result result) {
        if (isCancelled()) {
            onCancelled(result);
        } else {
            onPostExecute(result);
        }
        mStatus = Status.FINISHED;
    }

至此AsyncTask怎麼實現串行異步任務的分析就結束了,至於並行則是直接把mFuture交給executeOnExecutor(Executor exec,Params... params) 傳進來的自定義線程池exec去執行,來實現並行執行。

最後再提一下AsyncTask的取消操作。

public final boolean cancel(boolean mayInterruptIfRunning) {
        return mFuture.cancel(mayInterruptIfRunning);
    }

AsyncTask的cancel直接調用mFuture的cancel方法。mFuture在調用了cancel後,會回調mFuture的done()方法。

mFuture = new FutureTask<Result>(mWorker) {
            @Override
            protected void done() {
                try {
                    final Result result = get();

                    postResultIfNotInvoked(result);
                } catch (InterruptedException e) {
                    android.util.Log.w(LOG_TAG, e);
                } catch (ExecutionException e) {
                    throw new RuntimeException("An error occured while executing doInBackground()",
                            e.getCause());
                } catch (CancellationException e) {
                    postResultIfNotInvoked(null);
                } catch (Throwable t) {
                    throw new RuntimeException("An error occured while executing "
                            + "doInBackground()", t);
                }
            }
        };

done()方法中get()會拋出CancellationException異常,然後執行postResultIfNotInvoked(null);

發佈了47 篇原創文章 · 獲贊 3 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章