1. 程式人生 > >從原始碼分析AsyncTask執行流程和原理

從原始碼分析AsyncTask執行流程和原理

本篇文章將從大體上分析AsyncTask的原理,不會涉及過多的細節。AsyncTask現在已經不再流行了,但作為學習還是要了解下。

使用方法

下面是AsyncTask一般的使用場景,相信使用過AsyncTask的人都不會覺得陌生

class MyAsyncTask extends AsyncTask<Void,Void,Void>{
​
        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            //做初始化操作
        }
​
        @Override
        protected Void doInBackground(Void... voids) {
            boolean tag = true;
            while(tag){
                //耗時操作
                publishProgress();
            }
            return null;
        }
​
        @Override
        protected void onProgressUpdate(Void... values) {
            super.onProgressUpdate(values);
        }
​
        @Override
        protected void onPostExecute(Void aVoid) {
            super.onPostExecute(aVoid);
            //處理執行的結果
        }
    }
​
    MyAsyncTask task = new MyAsyncTask();
task.execute();

原始碼分析

下面從execute方法開始分析

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

內部呼叫了executeOnExecutor方法,並且傳了一個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() {//對引數r進一步封裝
            public void run() {
                try {
                    r.run();
                } finally {
                    //執行完一個任務之後,繼續取出另一個任務執行
                    scheduleNext();
                }
            }
        });
        if (mActive == null) {
            //如果當前沒有正在執行的任務,則從mTasks佇列取出一個任務去執行
            scheduleNext();
        }
    }
​
    protected synchronized void scheduleNext() {
        if ((mActive = mTasks.poll()) != null) {
            //THREAD_POOL_EXECUTOR才是正在執行任務的Executor
            THREAD_POOL_EXECUTOR.execute(mActive);
        }
    }
}

可以看到sDefaultExecutor是SerialExecutor類的物件,SerialExecutor實現了Excutor介面,並重寫了execute方法。SerialExecutor裡面有個ArrayDeque物件MTasks,在execute方法裡面,呼叫了mTasks的offer方法將一個Runnable物件加入佇列中。注意,並不是直接把引數Runnable物件加入,而是新new了一個Runnable,然後在新new的Runnable物件的run方法裡面,呼叫了傳遞引數Runnable物件的run方法,最後還呼叫了scheduleNext()方法。通過這種邏輯實現了序列執行任務,而不是並行執行。在scheduleNext方法裡面,呼叫了THREAD_POOL_EXECUTOR.execute(mActive);可以看到THREAD_POOL_EXECUTOR才是真正執行任務的Executor,而sDefaultExecutor只是用於做序列處理。

我們接著看回executeOnExecutor()方法

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:
                //一個task只能執行一次
                throw new IllegalStateException("Cannot execute task:"
                        + " the task has already been executed "
                        + "(a task can be executed only once)");
        }
    }
​
    mStatus = Status.RUNNING;
​
    onPreExecute();//先呼叫onPreExceute方法。所以execute()要在主執行緒呼叫才能保證                   
                   //onPreExecute()在主執行緒執行
​
    mWorker.mParams = params;//儲存接收到的引數,到時傳給doInBackground()方法
    exec.execute(mFuture);//執行mFuture
​
    return this;
}

可以看到executeOnExecutor方法裡面先呼叫了onPreExecute()方法,最終呼叫exec.execute(mFuture)開始執行任務。mFuture物件是在構造方法裡面建立的。

AsyncTask的構造方法

/**
 * Creates a new asynchronous task. This constructor must be invoked on the UI thread.
 *
 * @hide
 */
public AsyncTask(@Nullable Looper callbackLooper) {
    //建立handler
    mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
        ? getMainHandler()
        : new Handler(callbackLooper);
​
    //建立WorkerRunnable物件
    mWorker = new WorkerRunnable<Params, Result>() {
        public Result call() throws Exception {
            mTaskInvoked.set(true);
            Result result = null;
            try {
                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                //doInBackground方法執行在子執行緒
                result = doInBackground(mParams);
                Binder.flushPendingCommands();
            } catch (Throwable tr) {
                mCancelled.set(true);
                throw tr;
            } finally {
                //執行結果傳送出去
                postResult(result);
            }
            return result;
        }
    };
​
    //建立FutureTask物件
    //mWorker的call方法在FutureTask的run方法裡面執行
    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 occurred while executing doInBackground()",
                        e.getCause());
            } catch (CancellationException e) {
                postResultIfNotInvoked(null);
            }
        }
    };
}

構造方法裡面建立了mFuture物件,並傳入了mWorker物件,FutureTask可以看做是一個可以取到執行結果的Runnable。mWorker是WorkerRunnable的物件,WorkerRunnable是實現了Callable介面的子類,只有call方法,call方法會在mFuture的run方法中被呼叫。call方法裡面得到doInBackground返回的結果,然後傳給了postResult()方法。

我們看下postResult()方法

private Result postResult(Result result) {
        @SuppressWarnings("unchecked")
        Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
                new AsyncTaskResult<Result>(this, result));
        message.sendToTarget();
        return result;
}

postResult()方法封裝了result,然後通過Handler物件處理結果,通過handler實現了從子執行緒到主執行緒的切換。

private static class InternalHandler extends Handler {
    public InternalHandler(Looper looper) {
        super(looper);
    }
​
    @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://接受publishProgress方法傳送過來的結果
                result.mTask.onProgressUpdate(result.mData);
                break;
        }
    }
}

handlerMessage呼叫了finish()方法

private void finish(Result result) {
    if (isCancelled()) {
        onCancelled(result);
    } else {
        onPostExecute(result);//onPostExecute()方法在這裡呼叫了
    }
    mStatus = Status.FINISHED;
}

這裡我們看到了熟悉的onPostExecute()回撥方法。如果該task是取消的就會回撥onCancelled()方法。

在handleMessage方法裡面還有另一個case:MESSAGE_POST_PROGRESS,這種情況呼叫了我們熟悉的onProgressUpdate()方法。我們重寫doInBackground()方法在裡面呼叫publishProgress()方法就會有了onProgressUpdate()方法回撥。

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

總結

AsyncTask實際上是封裝了連個執行緒池THREAD_POOL_EXECUTOR、sDefaultExecutor和一個Handler。sDefaultExecutor做序列執行的邏輯,THREAD_POOL_EXECUTOR是真正執行任務的執行緒池,Handler是用於執行緒的切換。

注意點

1、由於execute()方法直接呼叫了onPreExecute()方法,而onPreExecute()是需要在主執行緒的,所以execute()方法 需要在主執行緒操作

2、由於AsyncTask預設是序列執行任務的,所以AsyncTask不適合做太過於耗時的操作

3、executeOnExecutor()方法是public的,通過指定特定的Executor可以實現並行