1. 程式人生 > >Android AsyncTask 原始碼解析(張鴻洋版)

Android AsyncTask 原始碼解析(張鴻洋版)

1、概述

相信大家對AsyncTask都不陌生,對於執行耗時任務,然後更新UI是一把利器,當然也是替代Thread + Handler 的一種方式。如果你對Handler機制還不瞭解,請看:Android 非同步訊息處理機制 讓你深入理解 Looper、Handler、Message三者關係

2、簡單的例子

相信大家都寫過這樣的程式碼:

[java] view plain copy print?
  1. package com.example.zhy_asynctask_demo01;  
  2. import android.app.Activity;  
  3. import android.app.ProgressDialog;  
  4. import android.os.AsyncTask;  
  5. import android.os.Bundle;  
  6. import android.util.Log;  
  7. import android.widget.TextView;  
  8. publicclass MainActivity extends Activity  
  9. {  
  10.     privatestaticfinal String TAG = “MainActivity”;  
  11.     private ProgressDialog mDialog;  
  12.     private TextView mTextView;  
  13.     @Override
  14.     protected
    void onCreate(Bundle savedInstanceState)  
  15.     {  
  16.         super.onCreate(savedInstanceState);  
  17.         setContentView(R.layout.activity_main);  
  18.         mTextView = (TextView) findViewById(R.id.id_tv);  
  19.         mDialog = new ProgressDialog(this);  
  20.         mDialog.setMax(100);  
  21.         mDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);  
  22.         mDialog.setCancelable(false);  
  23.         new MyAsyncTask().execute();  
  24.     }  
  25.     privateclass MyAsyncTask extends AsyncTask<Void, Integer, Void>  
  26.     {  
  27.         @Override
  28.         protectedvoid onPreExecute()  
  29.         {  
  30.             mDialog.show();  
  31.             Log.e(TAG, Thread.currentThread().getName() + ” onPreExecute ”);  
  32.         }  
  33.         @Override
  34.         protected Void doInBackground(Void… params)  
  35.         {  
  36.             // 模擬資料的載入,耗時的任務
  37.             for (int i = 0; i < 100; i++)  
  38.             {  
  39.                 try
  40.                 {  
  41.                     Thread.sleep(80);  
  42.                 } catch (InterruptedException e)  
  43.                 {  
  44.                     e.printStackTrace();  
  45.                 }  
  46.                 publishProgress(i);  
  47.             }  
  48.             Log.e(TAG, Thread.currentThread().getName() + ” doInBackground ”);  
  49.             returnnull;  
  50.         }  
  51.         @Override
  52.         protectedvoid onProgressUpdate(Integer… values)  
  53.         {  
  54.             mDialog.setProgress(values[0]);  
  55.             Log.e(TAG, Thread.currentThread().getName() + ” onProgressUpdate ”);  
  56.         }  
  57.         @Override
  58.         protectedvoid onPostExecute(Void result)  
  59.         {  
  60.             // 進行資料載入完成後的UI操作
  61.             mDialog.dismiss();  
  62.             mTextView.setText(”LOAD DATA SUCCESS ”);  
  63.             Log.e(TAG, Thread.currentThread().getName() + ” onPostExecute ”);  
  64.         }  
  65.     }  
  66. }  
package com.example.zhy_asynctask_demo01;

import android.app.Activity;
import android.app.ProgressDialog;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;

public class MainActivity extends Activity
{

    private static final String TAG = "MainActivity";
    private ProgressDialog mDialog;
    private TextView mTextView;

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mTextView = (TextView) findViewById(R.id.id_tv);

        mDialog = new ProgressDialog(this);
        mDialog.setMax(100);
        mDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
        mDialog.setCancelable(false);

        new MyAsyncTask().execute();

    }

    private class MyAsyncTask extends AsyncTask<Void, Integer, Void>
    {

        @Override
        protected void onPreExecute()
        {
            mDialog.show();
            Log.e(TAG, Thread.currentThread().getName() + " onPreExecute ");
        }

        @Override
        protected Void doInBackground(Void... params)
        {

            // 模擬資料的載入,耗時的任務
            for (int i = 0; i < 100; i++)
            {
                try
                {
                    Thread.sleep(80);
                } catch (InterruptedException e)
                {
                    e.printStackTrace();
                }
                publishProgress(i);
            }

            Log.e(TAG, Thread.currentThread().getName() + " doInBackground ");
            return null;
        }

        @Override
        protected void onProgressUpdate(Integer... values)
        {
            mDialog.setProgress(values[0]);
            Log.e(TAG, Thread.currentThread().getName() + " onProgressUpdate ");
        }

        @Override
        protected void onPostExecute(Void result)
        {
            // 進行資料載入完成後的UI操作
            mDialog.dismiss();
            mTextView.setText("LOAD DATA SUCCESS ");
            Log.e(TAG, Thread.currentThread().getName() + " onPostExecute ");
        }
    }
}

進入某個Activity,Activity中需要的資料來自於網路或者其它耗時操作,可以在AsyncTask中onPreExecute完成一些準備操作,比如上例中顯示進度對話方塊;然後在doInBackground完成耗時操作,在進行耗時操作時還能不時的通過publishProgress給onProgressUpdate中傳遞引數,然後在onProgressUpdate中可以進行UI操作,比如上例更新進度條的進度;當耗時任務執行完成後,最後在onPostExecute進行設定控制元件資料更新UI等操作,例如隱藏進度對話方塊。

效果圖:


3、原始碼解析

注:本篇原始碼分析基於Andorid-17,因為和3.0之前版本變動較大,有必要標出。

那麼大家一定好奇,AsyncTask在Android中是如何實現的,下面進行原始碼分析:從我們的執行非同步任務的起點開始,進入execute方法:

[java] view plain copy print?在CODE上檢視程式碼片派生到我的程式碼片
  1. publicfinal AsyncTask<Params, Progress, Result> execute(Params… params) {  
  2.         return executeOnExecutor(sDefaultExecutor, params);  
  3. }  
  4. publicfinal AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,  
  5.             Params… params) {  
  6.         if (mStatus != Status.PENDING) {  
  7.             switch (mStatus) {  
  8.                 case RUNNING:  
  9.                     thrownew IllegalStateException(“Cannot execute task:”
  10.                             + ” the task is already running.”);  
  11.                 case FINISHED:  
  12.                     thrownew IllegalStateException(“Cannot execute task:”
  13.                             + ” the task has already been executed ”
  14.                             + ”(a task can be executed only once)”);  
  15.             }  
  16.         }  
  17.         mStatus = Status.RUNNING;  
  18.         onPreExecute();  
  19.         mWorker.mParams = params;  
  20.         exec.execute(mFuture);  
  21.         returnthis;  
  22.     }  
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;
    }
18行:設定當前AsyncTask的狀態為RUNNING,上面的switch也可以看出,每個非同步任務在完成前只能執行一次。
20行:執行了onPreExecute(),當前依然在UI執行緒,所以我們可以在其中做一些準備工作。
22行:將我們傳入的引數賦值給了mWorker.mParams
23行:exec.execute(mFuture)

相信大家對22行出現的mWorker,以及23行出現的mFuture都會有些困惑。
mWorker找到這個類:

[java] view plain copy print?在CODE上檢視程式碼片派生到我的程式碼片
  1. privatestaticabstractclass WorkerRunnable<Params, Result> implements Callable<Result> {  
  2.         Params[] mParams;  
  3. }  
private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
        Params[] mParams;
}

可以看到是Callable的子類,且包含一個mParams用於儲存我們傳入的引數,下面看初始化mWorker的程式碼:
[java] view plain copy print?在CODE上檢視程式碼片派生到我的程式碼片
  1. public AsyncTask() {  
  2.         mWorker = new WorkerRunnable<Params, Result>() {  
  3.             public Result call() throws Exception {  
  4.                 mTaskInvoked.set(true);  
  5.                 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);  
  6.                 //noinspection unchecked
  7.                 return postResult(doInBackground(mParams));  
  8.             }  
  9.         };  
  10. //….
  11. }  
public AsyncTask() {
        mWorker = new WorkerRunnable<Params, Result>() {
            public Result call() throws Exception {
                mTaskInvoked.set(true);

                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                //noinspection unchecked
                return postResult(doInBackground(mParams));
            }
        };
//….

}

可以看到mWorker在構造方法中完成了初始化,並且因為是一個抽象類,在這裡new了一個實現類,實現了call方法,call方法中設定mTaskInvoked=true,且最終呼叫doInBackground(mParams)方法,並返回Result值作為引數給postResult方法.可以看到我們的doInBackground出現了,下面繼續看:
[java] view plain copy print?在CODE上檢視程式碼片派生到我的程式碼片
  1. private Result postResult(Result result) {  
  2.         @SuppressWarnings(“unchecked”)  
  3.         Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT,  
  4.                 new AsyncTaskResult<Result>(this, result));  
  5.         message.sendToTarget();  
  6.         return result;  
  7. }  
  private Result postResult(Result result) {
        @SuppressWarnings("unchecked")
        Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT,
                new AsyncTaskResult<Result>(this, result));
        message.sendToTarget();
        return result;
}

可以看到postResult中出現了我們熟悉的非同步訊息機制,傳遞了一個訊息message, message.what為MESSAGE_POST_RESULT;message.object= new AsyncTaskResult(this,result);
[java] view plain copy print?在CODE上檢視程式碼片派生到我的程式碼片
  1. privatestaticclass AsyncTaskResult<Data> {  
  2.        final AsyncTask mTask;  
  3.        final Data[] mData;  
  4.        AsyncTaskResult(AsyncTask task, Data… data) {  
  5.            mTask = task;  
  6.            mData = data;  
  7.        }  
  8.    }  
 private static class AsyncTaskResult<Data> {
        final AsyncTask mTask;
        final Data[] mData;

        AsyncTaskResult(AsyncTask task, Data... data) {
            mTask = task;
            mData = data;
        }
    }

AsyncTaskResult就是一個簡單的攜帶引數的物件。

看到這,我相信大家肯定會想到,在某處肯定存在一個sHandler,且複寫了其handleMessage方法等待訊息的傳入,以及訊息的處理。

[java] view plain copy print?在CODE上檢視程式碼片派生到我的程式碼片
  1. privatestaticfinal InternalHandler sHandler = new InternalHandler();  
  2.     privatestaticclass InternalHandler extends Handler {  
  3.         @SuppressWarnings({“unchecked”“RawUseOfParameterizedType”})  
  4.         @Override
  5.         publicvoid handleMessage(Message msg) {  
  6.             AsyncTaskResult result = (AsyncTaskResult) msg.obj;  
  7.             switch (msg.what) {  
  8.                 case MESSAGE_POST_RESULT:  
  9.                     // There is only one result
  10.                     result.mTask.finish(result.mData[0]);  
  11.                     break;  
  12.                 case MESSAGE_POST_PROGRESS:  
  13.                     result.mTask.onProgressUpdate(result.mData);  
  14.                     break;  
  15.             }  
  16.         }  
  17. }  
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;
            }
        }
}

哈哈,出現了我們的handleMessage,可以看到,在接收到MESSAGE_POST_RESULT訊息時,執行了result.mTask.finish(result.mData[0]);其實就是我們的AsyncTask.this.finish(result),於是看finish方法[java] view plain copy print?在CODE上檢視程式碼片派生到我的程式碼片
  1. privatevoid finish(Result result) {  
  2.         if (isCancelled()) {  
  3.             onCancelled(result);  
  4.         } else {  
  5.             onPostExecute(result);  
  6.         }  
  7.         mStatus = Status.FINISHED;  
  8.     }  
private void finish(Result result) {
        if (isCancelled()) {
            onCancelled(result);
        } else {
            onPostExecute(result);
        }
        mStatus = Status.FINISHED;
    }

可以看到,如果我們呼叫了cancel()則執行onCancelled回撥;正常執行的情況下呼叫我們的onPostExecute(result);主要這裡的呼叫是在handler的handleMessage中,所以是在UI執行緒中。如果你對非同步訊息機制不理解請看:Android 非同步訊息處理機制 讓你深入理解 Looper、Handler、Message三者關係
最後將狀態置為FINISHED。

mWoker看完了,應該到我們的mFuture了,依然實在構造方法中完成mFuture的初始化,將mWorker作為引數,複寫了其done方法。

[java] view plain copy print?在CODE上檢視程式碼片派生到我的程式碼片
  1. public AsyncTask() {  
  2.     …  
  3.         mFuture = new FutureTask<Result>(mWorker) {  
  4.             @Override
  5.             protectedvoid done() {  
  6.                 try {  
  7.                     postResultIfNotInvoked(get());  
  8.                 } catch (InterruptedException e) {  
  9.                     android.util.Log.w(LOG_TAG, e);  
  10.                 } catch (ExecutionException e) {  
  11.                     thrownew RuntimeException(“An error occured while executing doInBackground()”,  
  12.                             e.getCause());  
  13.                 } catch (CancellationException e) {  
  14.                     postResultIfNotInvoked(null);  
  15.                 }  
  16.             }  
  17.         };  
  18. }  
public AsyncTask() {
    ...
        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);
                }
            }
        };
}
16行:任務執行結束會呼叫:postResultIfNotInvoked(get());get()表示獲取mWorker的call的返回值,即Result.然後看postResultIfNotInvoked方法[java] view plain copy print?在CODE上檢視程式碼片派生到我的程式碼片
  1. privatevoid postResultIfNotInvoked(Result result) {  
  2.         finalboolean wasTaskInvoked = mTaskInvoked.get();  
  3.         if (!wasTaskInvoked) {  
  4.             postResult(result);  
  5.         }  
  6. }  
private void postResultIfNotInvoked(Result result) {
        final boolean wasTaskInvoked = mTaskInvoked.get();
        if (!wasTaskInvoked) {
            postResult(result);
        }
}
如果mTaskInvoked不為true,則執行postResult;但是在mWorker初始化時就已經將mTaskInvoked為true,所以一般這個postResult執行不到。
好了,到了這裡,已經介紹完了execute方法中出現了mWorker和mFurture,不過這裡一直是初始化這兩個物件的程式碼,並沒有真正的執行。下面我們看真正呼叫執行的地方。
execute方法中的:
還記得上面的execute中的23行:exec.execute(mFuture)

exec為executeOnExecutor(sDefaultExecutor, params)中的sDefaultExecutor

下面看這個sDefaultExecutor
[java] view plain copy print?在CODE上檢視程式碼片派生到我的程式碼片
  1. privatestaticvolatile Executor sDefaultExecutor = SERIAL_EXECUTOR;  
  2. publicstaticfinal Executor SERIAL_EXECUTOR = new SerialExecutor();  
  3. privatestaticclass SerialExecutor implements Executor {  
  4.         final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();  
  5.         Runnable mActive;  
  6.         publicsynchronizedvoid execute(final Runnable r) {  
  7.             mTasks.offer(new Runnable() {  
  8.                 publicvoid run() {  
  9.                     try {  
  10.                         r.run();  
  11.                     } finally {  
  12.                         scheduleNext();  
  13.                     }  
  14.                 }  
  15.             });  
  16.             if (mActive == null) {  
  17.                 scheduleNext();  
  18.             }  
  19.         }  
  20.         protectedsynchronizedvoid scheduleNext() {  
  21.             if ((mActive = mTasks.poll()) != null) {  
  22.                 THREAD_POOL_EXECUTOR.execute(mActive);  
  23.             }  
  24.         }  
  25. }  
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
public static final Executor SERIAL_EXECUTOR = new 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);
            }
        }
}
可以看到sDefaultExecutor其實為SerialExecutor的一個例項,其內部維持一個任務佇列;直接看其execute(Runnable runnable)方法,將runnable放入mTasks隊尾;
16-17行:判斷當前mActive是否為空,為空則呼叫scheduleNext方法
20行:scheduleNext,則直接取出任務佇列中的隊首任務,如果不為null則傳入THREAD_POOL_EXECUTOR進行執行。
下面看THREAD_POOL_EXECUTOR為何方神聖:
[java] view plain copy print?在CODE上檢視程式碼片派生到我的程式碼片
  1. publicstaticfinal Executor THREAD_POOL_EXECUTOR  
  2.           =new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,  
  3.                     TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);  
public static final Executor THREAD_POOL_EXECUTOR
          =new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
                    TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
可以看到就是一個自己設定引數的執行緒池,引數為:[java] view plain copy print?在CODE上檢視程式碼片派生到我的程式碼片
  1. privatestaticfinalint CORE_POOL_SIZE = 5;  
  2. privatestaticfinalint MAXIMUM_POOL_SIZE = 128;  
  3. privatestaticfinalint KEEP_ALIVE = 1;  
  4. privatestaticfinal ThreadFactory sThreadFactory = new ThreadFactory() {  
  5. privatefinal AtomicInteger mCount = new AtomicInteger(1);  
  6. public Thread newThread(Runnable r) {  
  7.      returnnew Thread(r, “AsyncTask #” + mCount.getAndIncrement());  
  8.     }  
  9.  };  
  10. privatestaticfinal BlockingQueue<Runnable> sPoolWorkQueue =  
  11.             new LinkedBlockingQueue<Runnable>(10);  
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);

看到這裡,大家可能會認為,背後原來有一個執行緒池,且最大支援128的執行緒併發,加上長度為10的阻塞佇列,可能會覺得就是在快速呼叫138個以內的AsyncTask子類的execute方法不會出現問題,而大於138則會丟擲異常。
其實不是這樣的,我們再仔細看一下程式碼,回顧一下sDefaultExecutor,真正在execute()中呼叫的為sDefaultExecutor.execute:
[java] view plain copy print?在CODE上檢視程式碼片派生到我的程式碼片
  1. privatestaticclass SerialExecutor implements Executor {  
  2.         final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();  
  3.         Runnable mActive;  
  4.         publicsynchronizedvoid execute(final Runnable r) {  
  5.             mTasks.offer(new Runnable() {  
  6.                 publicvoid run() {  
  7.                     try {  
  8.                         r.run();  
  9.                     } finally {  
  10.                         scheduleNext();  
  11.                     }  
  12.                 }  
  13.             });  
  14.             if (mActive == null) {  
  15.                 scheduleNext();  
  16.             }  
  17.         }  
  18.         protectedsynchronizedvoid scheduleNext() {  
  19.             if ((mActive = mTasks.poll()) != null) {  
  20.                 THREAD_POOL_EXECUTOR.execute(mActive);  
  21.             }  
  22.         }  
  23. }  
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);
            }
        }
}

可以看到,如果此時有10個任務同時呼叫execute(s synchronized)方法,第一個任務入隊,然後在mActive = mTasks.poll()) != null被取出,並且賦值給mActivte,然後交給執行緒池去執行。然後第二個任務入隊,但是此時mActive並不為null,並不會執行scheduleNext();所以如果第一個任務比較慢,10個任務都會進入佇列等待;真正執行下一個任務的時機是,執行緒池執行完成第一個任務以後,呼叫Runnable中的finally程式碼塊中的scheduleNext,所以雖然內部有一個執行緒池,其實呼叫的過程還是線性的。一個接著一個的執行,相當於單執行緒。

4、總結

到此原始碼解釋完畢,由於程式碼跨度比較大,我們再回顧一下:

[java] view plain copy print?在CODE上檢視程式碼片派生到我的程式碼片
  1. publicfinal AsyncTask<Params, Progress, Result> execute(Params… params) {  
  2.         return executeOnExecutor(sDefaultExecutor, params);  
  3. }  
  4. publicfinal AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,  
  5.             Params… params) {  
  6.         if (mStatus != Status.PENDING) {  
  7.             switch (mStatus) {  
  8.                 case RUNNING:  
  9.                     thrownew IllegalStateException(“Cannot execute task:”
  10.                             + ” the task is already running.”);  
  11.                 case FINISHED:  
  12.