面試的時候在問線程通訊的時候很多人都會說到 AsyncTask陪汽,但是問到具體實現(xiàn)原理的時候發(fā)現(xiàn)很多人都不清楚昧谊,甚至有很多都是工作好幾年的,感覺也是挺有意思鸽斟。這里大概介紹一下吧(怎么感覺這篇文章完全是在湊字數(shù)拔创?)。
組成 & 目的
官網(wǎng)資料
先列一下官方資料:Android doc AsyncTask富蓄,源代碼位于 AsyncTask.java剩燥,七百行多一點的代碼(排除注釋后只有不到三百行,我寫的其實大多都是廢話立倍,看源碼最清晰了)灭红。
組成
AsyncTask 主要包含兩部分,靜態(tài)線程池 + handler口注。
靜態(tài)線程池:因為耗時操作肯定要在子線程中處理(不然就阻塞 UI 線程啦)变擒,靜態(tài)線程池就是用來干這個的。
Handler:負責子線程與 UI 線程的通訊寝志。
目的
這個類的設計目的就是可以讓開發(fā)者只關心業(yè)務娇斑,因為 Android 暫時跳不出線程這個框框策添,還沒有讓開發(fā)者完全不關心線程問題的能力(簡而言之就是還需要區(qū)分主線程與子線程),但是在開發(fā)者使用時又會產(chǎn)生關于線程處理的多余代碼毫缆,所以 google 搞了一個 AsyncTask唯竹,主要的目的就是讓用戶只聚焦自己業(yè)務,線程的事情交由 AsyncTask 內(nèi)部處理(只不過我是使用不慣這貨)苦丁。
使用方式
基本使用方式如下(實例化 AsyncTask浸颓,然后 execute):
AsyncTask<String, Integer, Exception> asyncTask = new AsyncTask<String, Integer, Exception>() {
@Override
protected void onPreExecute() {
super.onPreExecute();
}
@Override
protected Exception doInBackground(String... params) {
return null;
}
@Override
protected void onProgressUpdate(Integer... values) {
}
@Override
protected void onPostExecute(Exception e) {
}
@Override
protected void onCancelled() {
}
};
asyncTask.execute("");
這是 google 想讓開發(fā)者關心的地方,總結(jié)就是三個參數(shù)旺拉,五個回調(diào)猾愿。
三個參數(shù)
參見上邊的代碼,三個參數(shù)主要是指<Params, Progress, Result>账阻,對應上邊的代碼就是<String, Integer, Exception>(方便區(qū)分蒂秘,專門用了三個不同的類型),
Params 是傳入的參數(shù)淘太,即 doInBackground 中的 params姻僧。
Progress 傳出參數(shù),表示進度類型蒲牧,即 onProgressUpdate 中的 values撇贺。
Exception 傳出參數(shù),表示返回值類型冰抢,即 onPostExecute 中的 e松嘶。
五個回調(diào)
五個回調(diào)也挨個說一下:
onPreExecute(主線程):開始真正的任務(doInBackground)前會調(diào)用此回調(diào),讓開發(fā)者做一些準備工作挎扰。
doInBackground(子線程):這就是真正的耗時任務了翠订。
onProgressUpdate(主線程):更新進度,當用戶主動調(diào)用 publishProgress 后遵倦,AsyncTask 會通過 handler 通知到主線程尽超,然后主線程調(diào)用 onProgressUpdate 來通知開發(fā)者。
onPostExecute(主線程):耗時任務執(zhí)行完以后梧躺,執(zhí)行此回調(diào)似谁。
onCancelled(主線程):如果耗時任務被 cancel 的話,則調(diào)用此回調(diào)掠哥。
(發(fā)現(xiàn)寫起來比預想的更難以解釋巩踏,其實看源代碼比看我解釋清楚多了,源代碼只有兩百多行续搀,為啥就這么多人不看呢)
好吧塞琼,我們還是來直接看代碼吧(其實我是真不想這么干)。
源碼(android-25)
public abstract class AsyncTask<Params, Progress, Result> {
// 顧名思義目代,CPU 的數(shù)量屈梁,主要是用來計算線程池默認包含線程的數(shù)量(最小值)
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
// 線程池包含線程的最小數(shù)量(當有新任務時嗤练,如果線程池中線程小于此值,則會創(chuàng)建新線程在讶,即使其他已有線程處于閑置狀態(tài))
private static final int CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4));
// 線程池的最大數(shù)量(超了就只能等著現(xiàn)有的某個線程執(zhí)行完了)
private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
// 已經(jīng)執(zhí)行任務結(jié)束的線程的續(xù)命時間(過了就被回收了)
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());
}
};
// 任務隊列
private static final BlockingQueue<Runnable> sPoolWorkQueue = new LinkedBlockingQueue<Runnable>(128);
// ThreadPoolExecutor 的引用(關于 ThreadPoolExecutor构哺,就是線程池革答,這里不做過多介紹)
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);
threadPoolExecutor.allowCoreThreadTimeOut(true);
THREAD_POOL_EXECUTOR = threadPoolExecutor;
}
// 顧名思義,串行的執(zhí)行器曙强,至于其細節(jié)残拐,請看 SerialExecutor 的注釋
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
// 線程間通訊的標記,這個是用來標記傳遞的 Message 其中的內(nèi)容為結(jié)果
private static final int MESSAGE_POST_RESULT = 0x1;
// 線程間通訊的標記碟嘴,這個是用來標記傳遞的 Message 其中的內(nèi)容為進度
private static final int MESSAGE_POST_PROGRESS = 0x2;
// 默認的執(zhí)行器溪食,默認值為串行,可通過 setDefaultExecutor 函數(shù)設置
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
// AsyncTask 中全局的娜扇、單例的错沃、主線程的 handler,這個 handler 主要用來子線程往主線程通訊使用
private static InternalHandler sHandler;
// 一個 WorkerRunnable 的實例(成員變量雀瓢,具體 WorkerRunnable 是干嘛的枢析,可以看 WorkerRunnable 的注釋)
private final WorkerRunnable<Params, Result> mWorker;
// 一個 FutureTask 的實例(成員變量,同樣刃麸,具體 FutureTask 是干嘛的請看 FutureTask 的注釋)
private final FutureTask<Result> mFuture;
// 當前 AsyncTask 的狀態(tài)
private volatile Status mStatus = Status.PENDING;
// 標記是否已經(jīng)被取消了
private final AtomicBoolean mCancelled = new AtomicBoolean();
private final AtomicBoolean mTaskInvoked = new AtomicBoolean();
// 這也是比較坑的東西醒叁,串行控制器,所以現(xiàn)在 AsyncTask 沒有做其他設置的話泊业,默認是串行的
// 但是這貨卻只負責將具體的 Runnable 包裝了一下把沼,然后再扔給 THREAD_POOL_EXECUTOR,并且 THREAD_POOL_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() {
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);
}
}
}
// 三種狀態(tài)
public enum Status {
PENDING,
RUNNING,
FINISHED,
}
// 單例獲取 Handler(主線程的 Handler)
private static Handler getHandler() {
synchronized (AsyncTask.class) {
if (sHandler == null) {
sHandler = new InternalHandler();
}
return sHandler;
}
}
// 可以讓開發(fā)者主動調(diào)用來設置執(zhí)行器
public static void setDefaultExecutor(Executor exec) {
sDefaultExecutor = exec;
}
// 構(gòu)造函數(shù)智政,而且注釋明確寫著,這個函數(shù)必須要在主線程中調(diào)用
// 構(gòu)造函數(shù)就干了兩件事箱蝠,初始化 mWorker 與 mFuture
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 call 沒有被執(zhí)行的話,這通過此函數(shù)講結(jié)果返回給開發(fā)者
private void postResultIfNotInvoked(Result result) {
final boolean wasTaskInvoked = mTaskInvoked.get();
if (!wasTaskInvoked) {
postResult(result);
}
}
// 當任務執(zhí)行完成后垦垂,通過調(diào)用此函數(shù)將結(jié)果發(fā)送給主線程
private Result postResult(Result result) {
@SuppressWarnings("unchecked")
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
message.sendToTarget();
return result;
}
// 獲取當前 AsyncTask 狀態(tài)
public final Status getStatus() {
return mStatus;
}
// 需要開發(fā)者必須實現(xiàn)的任務執(zhí)行函數(shù)宦搬,此函數(shù)在工作線程執(zhí)行
@WorkerThread
protected abstract Result doInBackground(Params... params);
// 在執(zhí)行 doInBackground 前,給用戶一個回調(diào)劫拗,讓開發(fā)者做一些準備工作间校,此函數(shù)在主線程執(zhí)行
@MainThread
protected void onPreExecute() {
}
// 回調(diào)接口,可以將 doInBackground 返回的結(jié)果通過此回調(diào)返回給開發(fā)者(其實主要還是一個跨線程的問題)
@SuppressWarnings({"UnusedDeclaration"})
@MainThread
protected void onPostExecute(Result result) {
}
// 回調(diào)接口页慷,將進度通過此回調(diào)返回給開發(fā)者憔足,當開發(fā)者調(diào)用 publishProgress 才會執(zhí)行此回調(diào)(主要也還是因為跨線程的問題胁附,讓 sHandler 來將運行在子線程的數(shù)據(jù)傳送到主線程)
@SuppressWarnings({"UnusedDeclaration"})
@MainThread
protected void onProgressUpdate(Progress... values) {
}
// 回調(diào)接口,當開發(fā)者主動調(diào)用 cancel 時會通過此回調(diào)通知開發(fā)者
@SuppressWarnings({"UnusedParameters"})
@MainThread
protected void onCancelled(Result result) {
onCancelled();
}
// 回調(diào)接口滓彰,當開發(fā)者主動調(diào)用 cancel 時會通過此回調(diào)通知開發(fā)者
@MainThread
protected void onCancelled() {
}
// 獲取當前 AsyncTask 是否被 cancel
public final boolean isCancelled() {
return mCancelled.get();
}
// 主動 cancel 當前執(zhí)行的任務
public final boolean cancel(boolean mayInterruptIfRunning) {
mCancelled.set(true);
return mFuture.cancel(mayInterruptIfRunning);
}
// 獲取執(zhí)行結(jié)果控妻,注意這是一個同步函數(shù),只有運算結(jié)束后揭绑,此函數(shù)才會繼續(xù)執(zhí)行
public final Result get() throws InterruptedException, ExecutionException {
return mFuture.get();
}
// 獲取執(zhí)行結(jié)果弓候,這也是同步函數(shù),當設置的時間后如果執(zhí)行仍未結(jié)束他匪,則通過 TimeoutException 來告訴開發(fā)者
public final Result get(long timeout, TimeUnit unit) throws InterruptedException,
ExecutionException, TimeoutException {
return mFuture.get(timeout, unit);
}
// 開發(fā)者調(diào)用的執(zhí)行函數(shù)
@MainThread
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
// 開發(fā)者調(diào)用的執(zhí)行函數(shù)
@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;
}
// 開發(fā)者調(diào)用的執(zhí)行函數(shù)菇存,將 runnable 傳給 sDefaultExecutor
@MainThread
public static void execute(Runnable runnable) {
sDefaultExecutor.execute(runnable);
}
// 更新進度函數(shù),會通過 InternalHandler 把進度傳遞給主線程
@WorkerThread
protected final void publishProgress(Progress... values) {
if (!isCancelled()) {
getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
new AsyncTaskResult<Progress>(this, values)).sendToTarget();
}
}
// 結(jié)束的時候調(diào)用此函數(shù)邦蜜,然后調(diào)用回調(diào)通知開發(fā)者
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
// 主線程的 Handler依鸥,用于工作線程與主線程之間的通訊
private static class InternalHandler extends Handler {
public InternalHandler() {
super(Looper.getMainLooper());
}
@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;
}
}
}
// 雖然這貨不是一個 Runnable,但是其實就是把一些邏輯封裝到一起悼沈,可以讓其他線程直接調(diào)用一個函數(shù)就可以執(zhí)行了
// 具體肯以看 AsyncTask 構(gòu)造函數(shù)中 WorkerRunnable 的實例化代碼毕籽,主要就是把 doInBackground 等函數(shù)包裝了一下
private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
Params[] mParams;
}
@SuppressWarnings({"RawUseOfParameterizedType"})
private static class AsyncTaskResult<Data> {
final AsyncTask mTask;
final Data[] mData;
AsyncTaskResult(AsyncTask task, Data... data) {
mTask = task;
mData = data;
}
}
}
注意
需要注意的是 AsyncTask 不同版本的實現(xiàn)是不同的,這也是比較坑的地方井辆。