AsyncTask 源碼分析

轉載請註明出處:http://blog.csdn.net/vnanyesheshou/article/details/73743534

本文已授權微信公衆號 fanfan程序媛 獨家發佈 掃一掃文章底部的二維碼或在微信搜索 fanfan程序媛 即可關注

上一篇主要說了下AsyncTask的基本用法和注意事項。這篇主要從源碼的角度研究下AsyncTask的原理。

先說下AsyncTask類中表示狀態的一個枚舉類,代碼如下:

public enum Status {
    PENDING,
    RUNNING,
    FINISHED,
}

PENDING 表示尚未執行任務。
RUNNING 表示任務正在運行。
FINISHED 表示任務結束。
AsyncTask中有一個Status類型變量mStatus,初始值爲PENDING。
接着分析任務的執行方法,execute代碼如下:

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

第6行:首先判斷mStatus 的值,如果爲PENDING則向下運行,設置mStatus爲RUNNING;否則拋出異常。也就是說每個異步任務只能執行一次,多次運行會拋出異常。
第18行:調用onPreExecute()函數。這是在UI線程中。
第19行:將參數賦值給mWorker.mParams。
第20行: exec.execute(mFuture)。
這裏的mWorker、exec(sDefaultExecutor)、mFuture看的比較模糊。我們看一下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 {
                postResultIfNotInvoked(get());
            } 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);
            }
        }
    };
}

mWorker是WorkerRunnable類型實例,WorkerRunnable代碼如下:

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

WorkerRunnable類是AsyncTask內部的一個抽象類,它實現了Callable接口,其中參數mParams用來保存傳入的參數。mWorker實現了Callable中的call()方法。Callable類似於Runnable的接口,實現Callable接口和Runnable都是可被其他線程執行的任務。
Callable定義的方法是call,Runnalbe定義的是run。
mWorker 的call方法中設置線程優先級爲後臺級別。然後調用AsyncTask的doInBackground方法(在子線程中)。

mFuture是FutureTask的實例(java.util.concurrent.FutureTask),FutureTask是一個可以中途取消的異步計算類。mFuture實例中,將會調用mWorker做任務,完成後會調用其done方法。

exec是由函數execute(Params…)傳過來的參數sDefaultExecutor。sDefaultExecutor的初始化如下:

public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;

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

sDefaultExecutor 是SerialExecutor的實例,SerialExecutor實現了Executor接口,該類中有一個任務隊列,任務執行execute,然後 exec.execute(mFuture)會調用到SerialExecutor的execute方法。
第9行 將任務添加到任務隊列中。
第14行 該任務執行完後,調用scheduleNext,執行下一個任務。
第18行 判斷mActive 是否爲null,爲空則調用scheduleNext。這表示任務是一個一個執行(串行)。
scheduleNext函數從任務隊列取出首任務,如果不爲null,則傳入THREAD_POOL_EXECUTOR執行該任務。

多個任務依次調用execute方法。第一個任務入隊,mActive 爲null,執行scheduleNext,從隊列中取出第一個任務,交給線程池去執行。第二個任務入隊,mActive此時不爲空,所以先不執行該任務。之後的各個任務也都添加到隊列中,不會串行執行。前面的任務執行完後,會執行Runnable中的finally代碼塊中的scheduleNext函數,然後從隊列中取出任務,交給線程池執行。

接着看THREAD_POOL_EXECUTOR:

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是新建的一個線程池執行器,用於管理線程的執行。

接着看mFuture。
mFuture的done()方法中,如果任務順利完成,則調用postResultIfNotInvoked(get()),get()方法用來獲取執行任務的結果;如果捕捉到CancellationException則調用postResultIfNotInvoked(null)。
接着看postResultIfNotInvoked

private void postResultIfNotInvoked(Result result) {
    final boolean wasTaskInvoked = mTaskInvoked.get();
    if (!wasTaskInvoked) {
        postResult(result);
    }
}

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

postResultIfNotInvoked函數調用postResult函數。

第10行 創建AsyncTaskResult對象,保存異步任務的結果及對應的任務。
第11行 將message發送給Handler進行處理。

看下Handler的代碼:

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:
                result.mTask.finish(result.mData[0]);
                break;
            case MESSAGE_POST_PROGRESS:
                result.mTask.onProgressUpdate(result.mData);
                break;
        }
    }
}

接收到MESSAGE_POST_RESULT消息,調用AsyncTask的finish方法。

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

第2行,判斷任務是否取消,如果取消則回調onCancelled(Result)方法。否則調用onPostExecute(Result)方法。
第7行,將任務狀態設置爲FINISHED。

publishProgress

protected final void publishProgress(Progress... values) {
    if (!isCancelled()) {
        sHandler.obtainMessage(MESSAGE_POST_PROGRESS,
                new AsyncTaskResult<Progress>(this, values)).sendToTarget();
    }
}

通過調用publishProgress來更新任務進度。該方法中先判斷任務是否取消,如果取消則不在處理。否則向Handler發送消息。
Handler接收到MESSAGE_POST_PROGRESS消息後,調用AsyncTask的onProgressUpdate()方法,更新進度。

到此AsyncTask就說的差不多了。AsyncTask是對線程池、Handler的良好封裝,是我們使用更加簡單方便。但是AsyncTask使用也有一定的缺陷,長時間的任務不建議使用AsyncTask。

歡迎掃一掃關注我的微信公衆號,定期推送優質技術文章:

這裏寫圖片描述

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