[TOC]
關于 Android 源碼分析,引用郭霖老師博客的一段話:
> 簡單概括就是八個字:抽絲剝繭、點到即止。應該認準一個功能點,然后去分析這個功能點是如何實現的。但只要去追尋主體的實現邏輯即可,千萬不要試圖去搞懂每一行代碼都是什么意思,那樣很容易會陷入到思維黑洞當中,而且越陷越深。因為這些龐大的系統都不是由一個人寫出來的,每一行代碼都想搞明白,就會感覺自己是在盲人摸象,永遠也研究不透。如果只是去分析主體的實現邏輯,那么就有比較明確的目的性,這樣閱讀源碼會更加輕松,也更加有成效。
本文不是原創,是在閱讀了互聯網上各位大神關于 AsyncTask 源碼分析的文章后,自己對于 AsyncTask 進行的一遍分析,雖不是原創,但自己順著思路捋一遍,并敲下本文后,感覺對于 AsyncTask 的用法以及原理的理解更加深刻了。
本文參考資料:
[Android中AsyncTask使用詳解–孫群](http://blog.csdn.net/iispring/article/details/50639090)
[Android異步任務AsyncTask的使用與原理分析–開心陽](http://blog.csdn.net/shakespeare001/article/details/51720548)
[Android AsyncTask完全解析,帶你從源碼的角度徹底理解–郭霖](http://blog.csdn.net/guolin_blog/article/details/11711405)
AsyncTask 的基礎使用
AsyncTask 是一個抽象類,必須寫一個子類繼承它,在子類中完成異步操作。AsyncTask 抽象類指定了3個泛型類型參數:
```java
public abstract class AsyncTask<Params, Progress, Result> {
...
}
```
三個泛型類型參數的含義如下:
* Params:開始異步任務執行時傳入的參數類型,即 doInBackground()方法中的參數類型;
* Progress:異步任務執行過程中,返回進度值的類型,即在 doInBackground 中調用 publishProgress()時傳入的參數類型;
* Result:異步任務執行完成后,返回的結果類型,即 doInBackground()方法的返回值類型;
AsyncTask 的回調方法包括:
* onPreExecute():在執行后臺操作之前調用,運行在主線程中;
* doInBackground():核心方法,執行后臺操作的方法,必須實現的一個方法,運行在子線程中;
* onPostExecute():后臺操作完成后調用,運行在主線程中;
* onProgressUpdate():在下載操作 doInBackground()中調用 publishProgress()時的回調方法,用于更新下載進度,運行在主線程中;
# 使用注意事項
* 對于一個 AsyncTack 的實例,只能執行一次 execute 方法,在該實例上第二次執行 execute 方法時就會拋出異常。
* AsyncTask 在最早的版本中用一個單一的后臺線程串行執行多個 AsyncTask 實例的任務,從 Android 1.6(DONUT)開始,AsyncTask 用線程池并行執行異步任務,但是從Android 3.0(HONEYCOMB)開始為了避免并行執行導致的常見錯誤,AsyncTask 又開始默認用單線程作為工作線程處理多個任務。
從Android 3.0開始 AsyncTask 增加了 executeOnExecutor 方法,用該方法可以讓 AsyncTask 并行處理任務,該方法的方法簽名如下所示:
```java
public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
Params... params)
```
第一個參數表示 exec 是一個 Executor 對象,為了讓 AsyncTask 并行處理任務,通常情況下我們此處傳入 AsyncTask.THREAD_POOL_EXECUTOR 即可,AsyncTask.THREAD_POOL_EXECUTOR 是 AsyncTask 中內置的一個線程池對象,當然我們也可以傳入我們自己實例化的線程池對象。第二個參數 params 表示的是要執行的任務的參數。
# 整體流程
1、首先調用 AsyncTask 的構造方法,構造時對 Handler、WorkerRunnable(Callable) 和 FutureTask 進行初始化
2、然后調用 AsyncTask 的 execute 方法(可以手動設置 Executor,不設置則使用系統默認的 SerialExecutor)
3、首先判斷當前 AsyncTask 狀態,正在運行或者已經運行過就退出
4、調用 onPreExecute 執行準備工作
5、由 Executor 調用 FutureTask 的 run 方法,在 WorkerRunnable 中執行了 doInBackground
6、依舊是在 WorkerRunnable 中,調用 postResult,將執行結果通過 Handler 發送給主線程;調用 publishProgress 時,也是通過 Handler 將消息發送到主線程的消息隊列中
# 源碼解析
開始一個 AsyncTask 任務很簡單,只要執行 new AsyncTask().execute()方法即可。我們的源碼分析也從這里開始。
首先來看 AsyncTask 的構造函數:
```java
/**
* Creates a new asynchronous task. This constructor must be invoked on the UI thread.
*/
public AsyncTask() {
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
mTaskInvoked.set(true);
Result result = null;
try {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
//noinspection unchecked
result = doInBackground(mParams);
Binder.flushPendingCommands();
} catch (Throwable tr) {
mCancelled.set(true);
throw tr;
} finally {
postResult(result);
}
return result;
}
};
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);
}
}
};
}
```
可以看到,在構造函數中,初始化了兩個變量 mWorker 和 mFuture。首先看看 AsyncTask 的 execute()方法。
```java
@MainThread
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
```
很簡單,在主線程進行調用,返回 executeOnExecutor(sDefaultExecutor, params)方法的值,那么我們看看這個方法:
```java
@MainThread
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 的狀態進行了判斷,當 AysncTask 的狀態是 RUNNING 和 FINISHED 時,會拋出異常,這也是為什么一個任務實例只能被啟動一次的原因。executeOnExecutor()方法傳入兩個參數,一個是 Executor,一個是 Params。Params 就是我們執行 doInBackground 中的參數類型。那么 Executor 呢,可以在上一段代碼看到,傳遞來的參數是 sDefaultExecutor,它的初始化如下:
```java
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
```
在 executeOnExecutor 方法中我們可以看到,先執行了 onPreExecute()方法,是在主線程。接著執行 exec.execute(mFuture),那么 doInBackground()方法應該就和它有關系了。接下來看看 SerialExecutor 類的 execute 方法,源碼如下:
```java
public synchronized void execute(final Runnable r) {
mTasks.offer(new Runnable() {
public void run() {
try {
r.run();
} finally {
scheduleNext();
}
}
});
if (mActive == null) {
scheduleNext();
}
}
```
可以看到,其中執行了參數 Runnable 的 run() 方法,這個 Runnable 就是傳進來的 mFuture。那么看看 FutureTask 的 run()方法:
```java
public void run() {
if (state != NEW ||
!U.compareAndSwapObject(this, RUNNER, null, Thread.currentThread()))
return;
try {
Callable<V> c = callable;
if (c != null && state == NEW) {
V result;
boolean ran;
try {
result = c.call();
ran = true;
} catch (Throwable ex) {
result = null;
ran = false;
setException(ex);
}
if (ran)
set(result);
}
} finally {
// runner must be non-null until state is settled to
// prevent concurrent calls to run()
runner = null;
// state must be re-read after nulling runner to prevent
// leaked interrupts
int s = state;
if (s >= INTERRUPTING)
handlePossibleCancellationInterrupt(s);
}
}
```
在 run() 方法中執行了 Callable 的 call()方法,callable 又是誰呢,callable 就是在 FutureTask 初始化時傳進來的 mWorker。說明調用的是 mWorker 的 call()方法。去看看:
```java
public Result call() throws Exception {
mTaskInvoked.set(true);
Result result = null;
try {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
//noinspection unchecked
result = doInBackground(mParams);
Binder.flushPendingCommands();
} catch (Throwable tr) {
mCancelled.set(true);
throw tr;
} finally {
postResult(result);
}
return result;
}
```
在這段代碼中,終于看到我們的 doInBackground()方法,此時依舊是在工作線程中運行。緊接著是 postResult(result),這其中又做了什么呢:
```java
private Result postResult(Result result) {
@SuppressWarnings("unchecked")
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
message.sendToTarget();
return result;
}
```
查看源碼得知,getHandler()返回的是 InternalHandler 的實例對象,那么就要去看看 InternalHandler 的 handleMessage()方法了。
```java
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;
}
}
```
可以看到,當 msg 的 what 值為 MESSAGE_POST_RESULT 時,代表工作線程的任務執行完成,執行 finish()方法。what 值為 MESSAGE_POST_PROGRESS 時,執行 onProgressUpdate(),也就是調用 publishProgress()時的回調方法。看一看 finish() 方法:
```java
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
```
當前任務被取消時,調用 onCancelled()方法,否則調用 onPostExecute()方法。最后看一下 publishProgress()的源碼:
```java
@WorkerThread
protected final void publishProgress(Progress... values) {
if (!isCancelled()) {
getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
new AsyncTaskResult<Progress>(this, values)).sendToTarget();
}
}
```
至此,主要的源碼就看完了,可以看到 AsyncTask 是對 Handler、Message 機制的一種封裝,使得我們的調用更加簡潔。
- 導讀
- Java知識
- Java基本程序設計結構
- 【基礎知識】Java基礎
- 【源碼分析】Okio
- 【源碼分析】深入理解i++和++i
- 【專題分析】JVM與GC
- 【面試清單】Java基本程序設計結構
- 對象與類
- 【基礎知識】對象與類
- 【專題分析】Java類加載過程
- 【面試清單】對象與類
- 泛型
- 【基礎知識】泛型
- 【面試清單】泛型
- 集合
- 【基礎知識】集合
- 【源碼分析】SparseArray
- 【面試清單】集合
- 多線程
- 【基礎知識】多線程
- 【源碼分析】ThreadPoolExecutor源碼分析
- 【專題分析】volatile關鍵字
- 【面試清單】多線程
- Java新特性
- 【專題分析】Lambda表達式
- 【專題分析】注解
- 【面試清單】Java新特性
- Effective Java筆記
- Android知識
- Activity
- 【基礎知識】Activity
- 【專題分析】運行時權限
- 【專題分析】使用Intent打開三方應用
- 【源碼分析】Activity的工作過程
- 【面試清單】Activity
- 架構組件
- 【專題分析】MVC、MVP與MVVM
- 【專題分析】數據綁定
- 【面試清單】架構組件
- 界面
- 【專題分析】自定義View
- 【專題分析】ImageView的ScaleType屬性
- 【專題分析】ConstraintLayout 使用
- 【專題分析】搞懂點九圖
- 【專題分析】Adapter
- 【源碼分析】LayoutInflater
- 【源碼分析】ViewStub
- 【源碼分析】View三大流程
- 【源碼分析】觸摸事件分發機制
- 【源碼分析】按鍵事件分發機制
- 【源碼分析】Android窗口機制
- 【面試清單】界面
- 動畫和過渡
- 【基礎知識】動畫和過渡
- 【面試清單】動畫和過渡
- 圖片和圖形
- 【專題分析】圖片加載
- 【面試清單】圖片和圖形
- 后臺任務
- 應用數據和文件
- 基于網絡的內容
- 多線程與多進程
- 【基礎知識】多線程與多進程
- 【源碼分析】Handler
- 【源碼分析】AsyncTask
- 【專題分析】Service
- 【源碼分析】Parcelable
- 【專題分析】Binder
- 【源碼分析】Messenger
- 【面試清單】多線程與多進程
- 應用優化
- 【專題分析】布局優化
- 【專題分析】繪制優化
- 【專題分析】內存優化
- 【專題分析】啟動優化
- 【專題分析】電池優化
- 【專題分析】包大小優化
- 【面試清單】應用優化
- Android新特性
- 【專題分析】狀態欄、ActionBar和導航欄
- 【專題分析】應用圖標、通知欄適配
- 【專題分析】Android新版本重要變更
- 【專題分析】唯一標識符的最佳做法
- 開源庫源碼分析
- 【源碼分析】BaseRecyclerViewAdapterHelper
- 【源碼分析】ButterKnife
- 【源碼分析】Dagger2
- 【源碼分析】EventBus3(一)
- 【源碼分析】EventBus3(二)
- 【源碼分析】Glide
- 【源碼分析】OkHttp
- 【源碼分析】Retrofit
- 其他知識
- Flutter
- 原生開發與跨平臺開發
- 整體歸納
- 狀態及狀態管理
- 零碎知識點
- 添加Flutter到現有應用
- Git知識
- Git命令
- .gitignore文件
- 設計模式
- 創建型模式
- 結構型模式
- 行為型模式
- RxJava
- 基礎
- Linux知識
- 環境變量
- Linux命令
- ADB命令
- 算法
- 常見數據結構及實現
- 數組
- 排序算法
- 鏈表
- 二叉樹
- 棧和隊列
- 算法時間復雜度
- 常見算法思想
- 其他技術
- 正則表達式
- 編碼格式
- HTTP與HTTPS
- 【面試清單】其他知識
- 開發歸納
- Android零碎問題
- 其他零碎問題
- 開發思路