前言
AsyncTask作為日常中一個經(jīng)常被使用到的類,知道他的工作原理也是一件非常重要的事情。
AsyncTask的使用代碼講解
AsyncTask使用方法已經(jīng)寫在下方的代碼中硝全。
/**
* AsyncTask存在三個泛型類型
* 1栖雾。Params:輸入數(shù)據(jù)
* 2。Progress:類似于用于進度更新的返回值
* 3伟众。Result:輸出的數(shù)據(jù)
*/
public class MyTask extends AsyncTask<String, Integer, String> {
/**
* 后臺操作
* @param strings
* @return
*/
@Override
protected String doInBackground(String... strings) {
return null;
}
/**
* 執(zhí)行前的預處理
*/
@Override
protected void onPreExecute() {
super.onPreExecute();
}
/**
* 執(zhí)行完成
* @param s
*/
@Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
}
/**
* 刷新得到的新更新
* @param values
*/
@Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
}
/**
* 任務取消
* @param s
*/
@Override
protected void onCancelled(String s) {
super.onCancelled(s);
}
/**
* 任務取消
*/
@Override
protected void onCancelled() {
super.onCancelled();
}
}
而Async的執(zhí)行流程如下圖所示
一般我們在代碼中只用執(zhí)行excute()
的函數(shù)析藕,在各個函數(shù)流程中給出相對應的操作。
對應的項目寫在我的Github倉庫
原理揭秘
MyTask task = new MyTask();
task.execute("赂鲤。噪径。");
步驟一:構造函數(shù)
在使用期間我們是需要實例化這個對象的,那么必經(jīng)的入口就是他的構造函數(shù)了数初。
public AsyncTask(@Nullable Looper callbackLooper) {
mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
? getMainHandler()
: new Handler(callbackLooper);
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
mTaskInvoked.set(true);
Result result = null;
// 找爱。。泡孩。
// 這里出現(xiàn)了我必須要重寫的函數(shù)3瞪恪!仑鸥!
result = doInBackground(mParams);
// 吮播。。眼俊。
// 把我們得到的數(shù)據(jù)傳輸了出去意狠,發(fā)送到哪里呢?
postResult(result);
return result;
}
};
mFuture = new FutureTask<Result>(mWorker) {
@Override
protected void done() {
// 疮胖。环戈。。
// 一個一定會執(zhí)行的函數(shù)
postResultIfNotInvoked(get());
// 澎灸。院塞。。
}
};
}
private void postResultIfNotInvoked(Result result) {
// 任務標記
final boolean wasTaskInvoked = mTaskInvoked.get();
// 任務為執(zhí)行性昭,則傳遞結果
if (!wasTaskInvoked) {
postResult(result);
}
}
在這里我看到的都是一些數(shù)據(jù)的初始化拦止,其實就是對任務完成的出口發(fā)送消息的定義、數(shù)據(jù)如何進行傳遞的定義等等糜颠。
步驟二:執(zhí)行汹族、execute()
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
進入執(zhí)行的第一句話,我們就能夠看到這樣一個函數(shù)其兴,從字面意思我就能夠知道了鞠抑,是將數(shù)據(jù)放入了一個線程池。
為了驗證我們之前所說的執(zhí)行流程我們先進入executeOnExecutor ()
的函數(shù)忌警。
public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
Params... params) {
// 。。法绵。箕速。
// 驗證了最開始的使用流程,excute執(zhí)行后朋譬,調(diào)用的是onPreExecute
onPreExecute();
// 開始對任務進行了處理
mWorker.mParams = params;
exec.execute(mFuture);
return this;
}
回到我們的執(zhí)行流程中盐茎,我們還沒有了解我們用的線程池他是怎樣的?
通過不斷的函數(shù)調(diào)用徙赢,我們能夠找到這樣的一個線程池內(nèi)部類字柠。
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(); // 1
}
}
});
if (mActive == null) {
scheduleNext(); // 1
}
}
protected synchronized void scheduleNext() {
// 從任務隊列中取出一個任務
if ((mActive = mTasks.poll()) != null) {
// 出現(xiàn)了另外一個線程池來進行執(zhí)行?狡赐?窑业??
THREAD_POOL_EXECUTOR.execute(mActive);
}
}
}
其他我們先并不予以關注枕屉,你是否看到了scheduleNext()
這個一定會被調(diào)用的函數(shù)呢常柄?而且里面又出現(xiàn)了一個線程池。原來這個THREAD_POOL_EXECUTOR
變量才是真正的執(zhí)行動作的線程池搀擂,那怎么去看待上面的那個線程池呢西潘?其實mTasks
這個變量已經(jīng)告訴我們答案了,他是一個進程存儲的進程任務隊列哨颂,并且execute()
是一個同步函數(shù)喷市,所以SerialExecutor
確切的說是一個進行按序任務調(diào)度的線程池。這樣也就證實了在很多博客中會說AsyncTask
是一個由兩個線程池和一個Handler組成的威恼。
調(diào)用順序的驗證
前面講過了execute()
后面調(diào)用的函數(shù)是onPreExecute()
品姓。而接下來的步驟就是doInBackground()
,回到先前的execute()
的代碼中沃测,我們知道會出現(xiàn)下面的代碼
exec.execute(mFuture);
// 上方操作調(diào)用的函數(shù)
public static void execute(Runnable runnable) {
sDefaultExecutor.execute(runnable);
}
我們已經(jīng)講過了sDefaultExecutor
他是一個任務調(diào)度的線程池缭黔,他會將任務發(fā)送給THREAD_POOL_EXECUTOR
進行完成,而他完成的mFuture
其實也是一個全局變量蒂破,我在構造函數(shù)中已經(jīng)提到過了馏谨。
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
mTaskInvoked.set(true);
Result result = null;
try {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
// 由線程池執(zhí)行完成時,用于回調(diào)的借口
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);
}
}
};
這里給讀者們看個全貌附迷,作為最后的回調(diào)接口中惧互,我們是否已經(jīng)關注到了一個函數(shù)doInBackground()
這個函數(shù)呢?
目前為止我們已經(jīng)完成了前三步喇伯,就差最后的一步onPostExecute()
的執(zhí)行出現(xiàn)了喊儡,其實在上文就已經(jīng)提到過了postResult(result)
這段代碼,就是進行一個結果的提交也就對應著我們所說的onPostExecute()
稻据。
我們通過深入了解可以知道艾猜,就是通過Handler
將一個數(shù)據(jù)傳出去,這個時候既然結束了,那就對應的是一個finish()
函數(shù)匆赃。
private static class InternalHandler extends Handler {
public InternalHandler(Looper looper) {
super(looper);
}
@SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})
@Override
public void handleMessage(Message msg) {
AsyncTaskResult<?> result = (AsyncTaskResult<?>) msg.obj;
switch (msg.what) {
case MESSAGE_POST_RESULT:
// 任務結束淤毛,返回數(shù)據(jù)。
result.mTask.finish(result.mData[0]);
break;
case MESSAGE_POST_PROGRESS:
// 得到了publish的操作算柳,來到這里操作數(shù)據(jù)低淡。
result.mTask.onProgressUpdate(result.mData);
break;
}
}
}
// 被調(diào)用的finish函數(shù)
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
到這里,我們完完整整的驗證了執(zhí)行的流程瞬项。
總結
以上就是我的學習成果蔗蹋,如果有什么我沒有思考到的地方或是文章內(nèi)存在錯誤,歡迎與我分享囱淋。