前言
-
AsyncTask
在Android
開發(fā)中是十分常見的 - 今天,我將全面講解
AsyncTask
的源碼旨指,希望你們會喜歡
Carson帶你學多線程系列
基礎匯總
Android多線程:基礎知識匯總
基礎使用
Android多線程:繼承Thread類使用(含實例教程)
Android多線程:實現(xiàn)Runnable接口使用(含實例教程)
復合使用
Android 多線程:AsyncTask使用教程(含實例講解)
Android 多線程:AsyncTask原理及源碼分析
Android多線程:HandlerThread使用教程(含實例講解)
Android多線程:HandlerThread原理及源碼分析
Android多線程:IntentService使用教程(含實例講解)
Android多線程:IntentService的原理及源碼分析
Android多線程:線程池ThreadPool全方位教學
相關使用
Android異步通信:這是一份全面&詳細的Handler機制學習攻略
Android多線程:手把手教你全面學習神秘的Synchronized關鍵字
Android多線程:帶你了解神秘的線程變量 ThreadLocal
目錄
1. 簡介
更詳細了解厦取,請看文章:Android 多線程:AsyncTask最詳細使用教程
本文主要講解其工作原理 & 源碼分析
2. 工作原理
2.1 儲備知識:線程
- 簡介
- 與進程的區(qū)別
2.2 具體原理介紹
-
AsyncTask
的實現(xiàn)原理 = 線程池 +Handler
其中:線程池用于線程調(diào)度憔杨、復用 & 執(zhí)行任務;
Handler
用于異步通信
- 其內(nèi)部封裝了2個線程池 + 1個
Handler
蒜胖,具體介紹如下:
3. 類 & 方法介紹
在進行源碼分析前消别,先介紹AsyncTask
中的類 & 核心方法
3.1 類定義
AsyncTask
類屬于抽象類,即使用時需 實現(xiàn)子類
public abstract class AsyncTask<Params, Progress, Result> {
...
}
// 類中參數(shù)為3種泛型類型
// 整體作用:控制AsyncTask子類執(zhí)行線程任務時各個階段的返回類型
// 具體說明:
// a. Params:開始異步任務執(zhí)行時傳入的參數(shù)類型台谢,對應excute()中傳遞的參數(shù)
// b. Progress:異步任務執(zhí)行過程中寻狂,返回下載進度值的類型
// c. Result:異步任務執(zhí)行完成后,返回的結(jié)果類型朋沮,與doInBackground()的返回值類型保持一致
// 注:
// a. 使用時并不是所有類型都被使用
// b. 若無被使用蛇券,可用java.lang.Void類型代替
// c. 若有不同業(yè)務,需額外再寫1個AsyncTask的子類
}
3.2 核心方法
-
AsyncTask
核心 & 常用的方法如下:
- 方法執(zhí)行順序如下
4. 源碼分析
- 本次源碼分析將根據(jù)
AsyncTask
的使用步驟講解
若不熟悉樊拓,請務必看文章:Android 多線程:AsyncTask最詳細使用教程
-
AsyncTask
的使用步驟有3個:
- 創(chuàng)建
AsyncTask
子類 & 根據(jù)需求實現(xiàn)核心方法 - 創(chuàng)建
AsyncTask
子類的實例對象(即 任務實例) - 手動調(diào)用
execute(()
從而執(zhí)行異步線程任務
- 具體介紹如下
/**
* 步驟1:創(chuàng)建AsyncTask子類
* 注:
* a. 繼承AsyncTask類
* b. 為3個泛型參數(shù)指定類型纠亚;若不使用,可用java.lang.Void類型代替
* c. 根據(jù)需求筋夏,在AsyncTask子類內(nèi)實現(xiàn)核心方法
*/
private class MyTask extends AsyncTask<Params, Progress, Result> {
....
// 方法1:onPreExecute()
// 作用:執(zhí)行 線程任務前的操作
// 注:根據(jù)需求復寫
@Override
protected void onPreExecute() {
...
}
// 方法2:doInBackground()
// 作用:接收輸入?yún)?shù)蒂胞、執(zhí)行任務中的耗時操作、返回 線程任務執(zhí)行的結(jié)果
// 注:必須復寫条篷,從而自定義線程任務
@Override
protected String doInBackground(String... params) {
...// 自定義的線程任務
// 可調(diào)用publishProgress()顯示進度, 之后將執(zhí)行onProgressUpdate()
publishProgress(count);
}
// 方法3:onProgressUpdate()
// 作用:在主線程 顯示線程任務執(zhí)行的進度
// 注:根據(jù)需求復寫
@Override
protected void onProgressUpdate(Integer... progresses) {
...
}
// 方法4:onPostExecute()
// 作用:接收線程任務執(zhí)行結(jié)果骗随、將執(zhí)行結(jié)果顯示到UI組件
// 注:必須復寫蛤织,從而自定義UI操作
@Override
protected void onPostExecute(String result) {
...// UI操作
}
// 方法5:onCancelled()
// 作用:將異步任務設置為:取消狀態(tài)
@Override
protected void onCancelled() {
...
}
}
/**
* 步驟2:創(chuàng)建AsyncTask子類的實例對象(即 任務實例)
* 注:AsyncTask子類的實例必須在UI線程中創(chuàng)建
*/
MyTask mTask = new MyTask();
/**
* 步驟3:手動調(diào)用execute(Params... params) 從而執(zhí)行異步線程任務
* 注:
* a. 必須在UI線程中調(diào)用
* b. 同一個AsyncTask實例對象只能執(zhí)行1次,若執(zhí)行第2次將會拋出異常
* c. 執(zhí)行任務中鸿染,系統(tǒng)會自動調(diào)用AsyncTask的一系列方法:onPreExecute() 指蚜、doInBackground()、onProgressUpdate() 涨椒、onPostExecute()
* d. 不能手動調(diào)用上述方法
*/
mTask.execute()摊鸡;
- 下面,我將根據(jù)上述使用步驟進行源碼分析
步驟1:創(chuàng)建AsyncTask子類
在該步驟中蚕冬,只需知道 “該類中復寫的方法將在后續(xù)源碼中調(diào)用” 即可
步驟2:創(chuàng)建AsyncTask子類的實例對象(即 任務實例)
/**
* 具體使用
*/
MyTask mTask = new MyTask();
/**
* 源碼分析:AsyncTask的構造函數(shù)
*/
public AsyncTask() {
// 1. 初始化WorkerRunnable變量 = 一個可存儲參數(shù)的Callable對象 ->>分析1
mWorker = new WorkerRunnable<Params, Result>() {
// 在任務執(zhí)行線程池中回調(diào):THREAD_POOL_EXECUTOR.execute()
// 下面會詳細講解
public Result call() throws Exception {
// 添加線程的調(diào)用標識
mTaskInvoked.set(true);
Result result = null;
try {
// 設置線程的優(yōu)先級
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
// 執(zhí)行異步操作 = 耗時操作
// 即 我們使用過程中復寫的耗時任務
result = doInBackground(mParams);
Binder.flushPendingCommands();
} catch (Throwable tr) {
mCancelled.set(true);// 若運行異常,設置取消的標志
throw tr;
} finally {
// 把異步操作執(zhí)行的結(jié)果發(fā)送到主線程
// 從而更新UI柱宦,下面會詳細講解
postResult(result);
}
return result;
}
};
// 2. 初始化FutureTask變量 = 1個FutureTask ->>分析2
mFuture = new FutureTask<Result>(mWorker) {
// done()簡介:FutureTask內(nèi)的Callable執(zhí)行完后的調(diào)用方法
// 作用:復查任務的調(diào)用、將未被調(diào)用的任務的結(jié)果通過InternalHandler傳遞到UI線程
@Override
protected void done() {
try {
// 在執(zhí)行完任務后檢查,將沒被調(diào)用的Result也一并發(fā)出 ->>分析3
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) {
//若 發(fā)生異常,則將發(fā)出null
postResultIfNotInvoked(null);
}
}
};
}
/**
* 分析1:WorkerRunnable類的構造函數(shù)
*/
private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
// 此處的Callable也是任務播瞳;
// 與Runnable的區(qū)別:Callable<T>存在返回值 = 其泛型
Params[] mParams;
}
/**
* 分析2:FutureTask類的構造函數(shù)
* 定義:1個包裝任務的包裝類
* 注:內(nèi)部包含Callable<T> 掸刊、增加了一些狀態(tài)標識 & 操作Callable<T>的接口
*/
public FutureTask(Callable<V> callable) {
if (callable == null)
throw new NullPointerException();
this.callable = callable;
this.state = NEW;
}
// 回到調(diào)用原處
/**
* 分析3:postResultIfNotInvoked()
*/
private void postResultIfNotInvoked()(Result result) {
// 取得任務標記
final boolean wasTaskInvoked = mTaskInvoked.get();
// 若任務無被執(zhí)行,將未被調(diào)用的任務的結(jié)果通過InternalHandler傳遞到UI線程
if (!wasTaskInvoked) {
postResult(result);
}
}
總結(jié):
- 創(chuàng)建了1個
WorkerRunnable
類 的實例對象 & 復寫了call()
方法 - 創(chuàng)建了1個
FutureTask
類 的實例對象 & 復寫了done()
步驟3:手動調(diào)用execute(Params... params)
/**
* 具體使用
*/
mTask.execute();
/**
* 源碼分析:AsyncTask的execute()
*/
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
// ->>分析1
}
/**
* 分析1:executeOnExecutor(sDefaultExecutor, params)
* 參數(shù)說明:sDefaultExecutor = 任務隊列 線程池類(SerialExecutor)的對象
*/
public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,Params... params) {
// 1. 判斷 AsyncTask 當前的執(zhí)行狀態(tài)
// PENDING = 初始化狀態(tài)
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)");
}
}
// 2. 將AsyncTask狀態(tài)設置為RUNNING狀態(tài)
mStatus = Status.RUNNING;
// 3. 主線程初始化工作
onPreExecute();
// 4. 添加參數(shù)到任務中
mWorker.mParams = params;
// 5. 執(zhí)行任務
// 此處的exec = sDefaultExecutor = 任務隊列 線程池類(SerialExecutor)的對象
// ->>分析2
exec.execute(mFuture);
return this;
}
/**
* 分析2:exec.execute(mFuture)
* 說明:屬于任務隊列 線程池類(SerialExecutor)的方法
*/
private static class SerialExecutor implements Executor {
// SerialExecutor = 靜態(tài)內(nèi)部類
// 即 是所有實例化的AsyncTask對象公有的
// SerialExecutor 內(nèi)部維持了1個雙向隊列赢乓;
// 容量根據(jù)元素數(shù)量調(diào)節(jié)
final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
Runnable mActive;
// execute()被同步鎖synchronized修飾
// 即說明:通過鎖使得該隊列保證AsyncTask中的任務是串行執(zhí)行的
// 即 多個任務需1個個加到該隊列中忧侧;然后 執(zhí)行完隊列頭部的再執(zhí)行下一個,以此類推
public synchronized void execute(final Runnable r) {
// 將實例化后的FutureTask類 的實例對象傳入
// 即相當于:向隊列中加入一個新的任務
mTasks.offer(new Runnable() {
public void run() {
try {
r.run();
} finally {
scheduleNext();->>分析3
}
}
});
// 若當前無任務執(zhí)行牌芋,則去隊列中取出1個執(zhí)行
if (mActive == null) {
scheduleNext();
}
}
// 分析3
protected synchronized void scheduleNext() {
// 1. 取出隊列頭部任務
if ((mActive = mTasks.poll()) != null) {
// 2. 執(zhí)行取出的隊列頭部任務
// 即 調(diào)用執(zhí)行任務線程池類(THREAD_POOL_EXECUTOR)->>繼續(xù)往下看
THREAD_POOL_EXECUTOR.execute(mActive);
}
}
}
總結(jié):
- 執(zhí)行任務前蚓炬,通過 任務隊列 線程池類(SerialExecutor)將任務按順序放入到隊列中;
通過同步鎖 修飾
execute()
從而保證AsyncTask中的任務是串行執(zhí)行的
- 之后的線程任務執(zhí)行是 通過任務線程池類(THREAD_POOL_EXECUTOR) 進行的躺屁。
繼續(xù)往下分析:THREAD_POOL_EXECUTOR.execute()
/**
* 源碼分析:THREAD_POOL_EXECUTOR.execute()
* 說明:
* a. THREAD_POOL_EXECUTOR實際上是1個已配置好的可執(zhí)行并行任務的線程池
* b. 調(diào)用THREAD_POOL_EXECUTOR.execute()實際上是調(diào)用線程池的execute()去執(zhí)行具體耗時任務
* c. 而該耗時任務則是步驟2中初始化WorkerRunnable實例對象時復寫的call()
* 注:下面先看任務執(zhí)行線程池的線程配置過程肯夏,看完后請回到步驟2中的源碼分析call()
*/
// 步驟1:參數(shù)設置
//獲得當前CPU的核心數(shù)
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
//設置線程池的核心線程數(shù)2-4之間,但是取決于CPU核數(shù)
private static final int CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4));
//設置線程池的最大線程數(shù)為 CPU核數(shù)*2+1
private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
//設置線程池空閑線程存活時間30s
private static final int KEEP_ALIVE_SECONDS = 30;
//初始化線程工廠
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());
}
};
//初始化存儲任務的隊列為LinkedBlockingQueue 最大容量為128
private static final BlockingQueue<Runnable> sPoolWorkQueue =
new LinkedBlockingQueue<Runnable>(128);
// 步驟2: 根據(jù)參數(shù)配置執(zhí)行任務線程池,即 THREAD_POOL_EXECUTOR
public static final Executor THREAD_POOL_EXECUTOR;
static {
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,
sPoolWorkQueue, sThreadFactory);
// 設置核心線程池的 超時時間也為30s
threadPoolExecutor.allowCoreThreadTimeOut(true);
THREAD_POOL_EXECUTOR = threadPoolExecutor;
}
// 請回到步驟2中的源碼分析call()
至此犀暑,我們回到步驟2中的源碼分析call()
/**
* 步驟2的源碼分析:AsyncTask的構造函數(shù)
*/
public AsyncTask() {
// 1. 初始化WorkerRunnable變量 = 一個可存儲參數(shù)的Callable對象
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
// 添加線程的調(diào)用標識
mTaskInvoked.set(true);
Result result = null;
try {
// 設置線程的優(yōu)先級
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
// 執(zhí)行異步操作 = 耗時操作
// 即 我們使用過程中復寫的耗時任務
result = doInBackground(mParams);
Binder.flushPendingCommands();
} catch (Throwable tr) {
mCancelled.set(true);// 若運行異常,設置取消的標志
throw tr;
} finally {
// 把異步操作執(zhí)行的結(jié)果發(fā)送到主線程
// 從而更新UI ->>分析1
postResult(result);
}
return result;
}
};
.....// 省略
}
/**
* 分析1:postResult(result)
*/
private Result postResult(Result result) {
@SuppressWarnings("unchecked")
// 創(chuàng)建Handler對象 ->> 源自InternalHandler類—>>分析2
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
// 發(fā)送消息到Handler中
message.sendToTarget();
return result;
}
/**
* 分析2:InternalHandler類
*/
private static class InternalHandler extends Handler {
// 構造函數(shù)
public InternalHandler() {
super(Looper.getMainLooper());
// 獲取的是主線程的Looper()
// 故 AsyncTask的實例創(chuàng)建 & execute()必須在主線程使用
}
@Override
public void handleMessage(Message msg) {
AsyncTaskResult<?> result = (AsyncTaskResult<?>) msg.obj;
switch (msg.what) {
// 若收到的消息 = MESSAGE_POST_RESULT
// 則通過finish() 將結(jié)果通過Handler傳遞到主線程
case MESSAGE_POST_RESULT:
result.mTask.finish(result.mData[0]); ->>分析3
break;
// 若收到的消息 = MESSAGE_POST_PROGRESS
// 則回調(diào)onProgressUpdate()通知主線程更新進度的操作
case MESSAGE_POST_PROGRESS:
result.mTask.onProgressUpdate(result.mData);
break;
}
}
}
/**
* 分析3:result.mTask.finish(result.mData[0])
*/
private void finish(Result result) {
// 先判斷是否調(diào)用了Cancelled()
// 1. 若調(diào)用了則執(zhí)行我們復寫的onCancelled()
// 即 取消任務時的操作
if (isCancelled()) {
onCancelled(result);
} else {
// 2. 若無調(diào)用Cancelled()驯击,則執(zhí)行我們復寫的onPostExecute(result)
// 即更新UI操作
onPostExecute(result);
}
// 注:不管AsyncTask是否被取消,都會將AsyncTask的狀態(tài)變更為:FINISHED
mStatus = Status.FINISHED;
}
總結(jié)
- 任務線程池類
(THREAD_POOL_EXECUTOR)
實際上是1個已配置好的可執(zhí)行并行任務的線程池 - 調(diào)用
THREAD_POOL_EXECUTOR.execute()
實際上是調(diào)用線程池的execute()
去執(zhí)行具體耗時任務 - 而該耗時任務則是步驟2中初始化
WorkerRunnable
實例對象時復寫的call()
內(nèi)容 - 在
call()
方法里耐亏,先調(diào)用 我們復寫的doInBackground(mParams)
執(zhí)行耗時操作 - 再調(diào)用
postResult(result)
徊都, 通過InternalHandler
類 將任務消息傳遞到主線程;根據(jù)消息標識(MESSAGE_POST_RESULT)
判斷广辰,最終通過finish()
調(diào)用我們復寫的onPostExecute(result)
暇矫,從而實現(xiàn)UI更新操作
至此,關于AsyncTask
的源碼 分析完畢择吊,附上一份最終總結(jié):
9. 總結(jié)
- 本文介紹了多線程中的
AsyncTask
的 工作原理 & 源碼分析李根,總結(jié)如下:
- 下一篇文章我將對講解
Android
多線程的相關知識,感興趣的同學可以繼續(xù)關注Carson_Ho的簡書
Carson帶你學多線程系列
基礎匯總
Android多線程:基礎知識匯總
基礎使用
Android多線程:繼承Thread類使用(含實例教程)
Android多線程:實現(xiàn)Runnable接口使用(含實例教程)
復合使用
Android 多線程:AsyncTask使用教程(含實例講解)
Android 多線程:AsyncTask原理及源碼分析
Android多線程:HandlerThread使用教程(含實例講解)
Android多線程:HandlerThread原理及源碼分析
Android多線程:IntentService使用教程(含實例講解)
Android多線程:IntentService的原理及源碼分析
Android多線程:線程池ThreadPool全方位教學
相關使用
Android異步通信:這是一份全面&詳細的Handler機制學習攻略
Android多線程:手把手教你全面學習神秘的Synchronized關鍵字
Android多線程:帶你了解神秘的線程變量 ThreadLocal
歡迎關注Carson_Ho的簡書
不定期分享關于安卓開發(fā)的干貨几睛,追求短房轿、平、快,但卻不缺深度冀续。