1. 程式人生 > >從原始碼分析AsyncTask

從原始碼分析AsyncTask

AsyncTask是Android提供的一個非同步處理的方式。該方式使用較為方便,與Handler相比在程式碼上顯得更簡潔。
先來看看使用AsyncTask常用到的幾個方法:
1.execute(Params… params),執行一個非同步任務,需要我們在程式碼中呼叫此方法,觸發非同步任務的執行。(在UI執行緒呼叫

2.onPreExecute(),在execute(Params… params)被呼叫後立即執行,一般用來在執行後臺任務前對UI做一些標記。

3.doInBackground(Params… params),在onPreExecute()完成後立即執行,用於執行較為費時的操作,此方法將接收輸入引數和返回計算結果。在執行過程中可以呼叫publishProgress(Progress… values)來更新進度資訊。

4.onProgressUpdate(Progress… values),在呼叫publishProgress(Progress… values)時,此方法被執行,直接將進度資訊更新到UI元件上。

5.onPostExecute(Result result),當後臺操作結束時,此方法將會被呼叫,計算結果將做為引數傳遞到此方法中,直接將結果顯示到UI元件上。
詳細的例子網上也很多了,此處不再列舉,以上也是引用的別人的部落格所述。
地址:http://blog.csdn.net/liuhe688/article/details/6532519
此篇主要是根據原始碼來分析AsyncTask的原理。

AsyncTask原始碼分析

老套路,先看看AsyncTask的建構函式。

/**
     * Creates a new asynchronous task. This constructor must be invoked on the UI thread.
     */
    public AsyncTask() {
    //WorkerRunnable 為一個繼承Callable<Result>介面的虛類
        mWorker = new WorkerRunnable<Params, Result>() {
            public
Result call() throws Exception { mTaskInvoked.set(true); Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); //noinspection unchecked //呼叫doInBackground 但並不在這開始執行 return postResult(doInBackground(mParams)); } }; mFuture = new FutureTask<Result>(mWorker) {//初始化mFuture @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); } } }; }

在建構函式中進行了一些初始化工作,並且最後都呼叫到了postResult,在postResultIfNotInvoked(get())中,其實最後也呼叫到了postResult。 這裡用到了
Java併發程式設計:Callable、Future和FutureTask。有興趣的可以看看。
在上面的程式碼中,當mWorker中定義的call方法被執行時,doInBackground就會開始執行,我們定義的後臺任務也就真正開始了。實際上mFuture物件封裝了call方法,當mFuture物件被提交到AsyncTask包含的執行緒池執行時,call方法就會被呼叫,我們定義的後臺任務也就開始執行了。到此,我們先記住要使doInBackground()方法執行,就需要mFuture被執行,但是執行的地方還沒找到。回想我們使用AsyncTask的時候,需要呼叫execute()方法,讓程式跑起來。拿我們就先看看這個方法。

 &emp;我們建立一個繼承於一個public abstract class AsyncTask

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

來看看executeOnExecutor方法 和sDefaultExecutor,params引數是一直傳到doInBackground方法的。
sDefaultExecutor是什麼呢?通過程式碼可以找到

public static final Executor SERIAL_EXECUTOR = Utils.hasHoneycomb() ? new SerialExecutor() :
            Executors.newSingleThreadExecutor(sThreadFactory);


private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;

sDefaultExecutor 要不是一個 SerialExecutor要不就是一個單執行緒池。來看看SerialExecutor到底是什麼。

private static class SerialExecutor implements Executor {

        //mTasks  快取佇列
        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);// 執行任務
            }
        }
    }

從上面的程式碼,可以看出首先由一個快取佇列mTasks ,該佇列通過offer新增任務,通過THREAD_POOL_EXECUTOR.execute(mActive)去執行任務。那麼接下來就是THREAD_POOL_EXECUTOR了。

 public static final Executor THREAD_POOL_EXECUTOR
            = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
            TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory,
            new ThreadPoolExecutor.DiscardOldestPolicy());

很明顯了THREAD_POOL_EXECUTOR就是一個執行緒池,並且規定了CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,TimeUnit.SECONDS等。從原始碼中也可以看到

    private static final int CORE_POOL_SIZE = 5;執行緒池大小5
    private static final int MAXIMUM_POOL_SIZE = 128;最大執行緒數128
    private static final int KEEP_ALIVE = 1;存活時間1s

接下來就是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:
                    throw new IllegalStateException("Cannot execute task:"
                            + " the task has already been executed "
                            + "(a task can be executed only once)");
            }
        }

        mStatus = Status.RUNNING;

        onPreExecute();//該方法被呼叫,一般用來在執行後臺任務前對UI做一些標記。

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

        return this;
    }

在程式碼的倒數第二行exec.execute(mFuture);這個方法。還記得之前mFuture物件麼,這就是他被執行的地方了。從而doInBackground方法也就能夠執行了,而且還由執行緒池進行控制。
以上為AsyncTask 呼叫流程的理解。