編輯:關於Android編程
AsyncTask 即 asynchronous task,異步任務。
AsyncTask實際上是圍繞Thread和Handler設計的一個輔助類,在內部是對Thread和Handler的一種封裝。AsyncTask的異步體現在由後台線程進行運算(訪問網絡等比較耗時的操作),然後將結果發布到用戶界面上來更新UI,使用AsyncTask使得我不用操作Thread和Handler。
new AsyncTask(){ //// 運行在主線程中,做預備工作///// onPreExecute(){ } // 運行在子線程中,做耗時操作 String doingBackGround(String s){ } // 運行在主線程中,耗時操作完成,更新UI onPostExecute(String s){ } }.execute(String);
AsyncTask用法比較簡單,Google設計這個類就是為了方便我們進行類似Handler這樣的異步操作。
接下來進入這篇文章的重點,我們從源碼角度來分析AsyncTask是如何實現的。
AsyncTask的execute方法
public final AsyncTask上面是execute方法,發現execute其實內部調用的executeOnExecutor方法,調用executeOnExecutor方法傳遞了兩個參數,這裡第一個傳遞了一個默認的執行器,關於這個sDefaultExecutor我們再來講,我們現在來看AsyncTask的流程設計。 我們來看這個executeOnExecutor方法,這裡將不重要的代碼略去了,其實這裡面的邏輯比較清晰。execute(Params... params) { return executeOnExecutor(sDefaultExecutor, params); }
public final AsyncTask第一步,onPreExecute與上面的介紹一樣,進行准備工作,這個就沒有必要分析,如果我們沒有重寫,就不會做相關的准備。我們主要第二步和第三步,第二步,把params參數賦值給mWorker,params是execute中傳遞過來的參數,同時也是泛型中第一個參數,將params賦值給mWorker,那麼mWorker是什麼呢?executeOnExecutor(Executor exec, Params... params) { ..... ..... mStatus = Status.RUNNING; //////////////////////////////// // 第一步:在主線程中執行准備操作//// onPreExecute(); // 第二步:把params參數賦值給mWorker mWorker.mParams = params; // 第三步:用線程池執行mFuture exec.execute(mFuture); /////////////////////// return this; }
AsyncTask的構造方法
我們繼續看源碼:主意到mWorker是在AsyncTask的構造方法中創建的。
public AsyncTask() {
mWorker = new WorkerRunnable() {
public Result call() throws Exception {
.....
}
};
mFuture = new FutureTask(mWorker) {
@Override
protected void done() {
.....
}
};
}
首先,mWorker在構造方法中創建,它是一個匿名內部類,那WorkerRunnable是個什麼東西呢?
private static abstract class WorkerRunnable我們發現WorkerRunnable其實就是一個Callable,同時在execute方法中mFuture也在這裡創建了出來,這裡會將mWorker傳遞到FutureTask中去,那麼將mFuture傳進去做了什麼什麼操作呢?implements Callable { Params[] mParams; }
public FutureTask(CallableFutureTask是java.util.concurrent,FutureTask繼承了Future,通過 Future 接口,可以嘗試取消尚未完成的任務,查詢任務已經完成還是取消了,以及提取(或等待)任務的結果值。 在AsyncTask的構造方法中,將mWorker傳進來,即將callable傳進來,因為mWorker就是callable。 這樣在上面的executeOnExecutor中的第三步中,==exec.execute(mFuture)== 用線程池來執行mFuture,其實就是執行mFuture中的run方法,我們來看FutureTask中的run方法:callable) { if (callable == null) throw new NullPointerException(); //////這裡將mWorker傳遞進來,其實就是callable/// ///////////// this.callable = callable; this.state = NEW; // ensure visibility of callable }
FutureTask中的run方法
public void run() {
if (state != NEW ||
!UNSAFE.compareAndSwapObject(this, runnerOffset,
null, Thread.currentThread()))
return;
try {
Callable c = callable;
if (c != null && state == NEW) {
V result;
boolean ran;
try {
//① 調用callable中的call方法,其實就是mWorker中的call方法
//並且將結果賦值給result
result = c.call();
ran = true;
} catch (Throwable ex) {
result = null;
ran = false;
setException(ex);
}
if (ran)
//② 調用自己內部的set方法設置結果
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);
}
}
在FutureTask中的run方法,我們需要關注兩個地方,第一個,就是上面代碼片段的①處,這裡調用了mWorker中的call方法,這樣我們再回頭來看mWorker中的call方法。
mWorker = new WorkerRunnable() { public Result call() throws Exception { mTaskInvoked.set(true); Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); //noinspection unchecked return postResult(doInBackground(mParams)); } };
private Result postResult(Result result) {
@SuppressWarnings("unchecked")
Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult(this, result));
message.sendToTarget();
return result;
}
在mWorker中call方法中主要就是執行耗時操作,正是doInBackground方法,並且將執行的結果result返回回去,用postResult對doInBackground進行包裹則是為了運用Handler機制來更新UI。 接下來我們看FutureTask中run方法中的②處,調用了FutureTask自己的set方法。
protected void set(V v) {
if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
outcome = v;
UNSAFE.putOrderedInt(this, stateOffset, NORMAL); // final state
finishCompletion();
}
}
private void finishCompletion() {
// assert state > COMPLETING;
for (WaitNode q; (q = waiters) != null;) {
if (UNSAFE.compareAndSwapObject(this, waitersOffset, q, null)) {
for (;;) {
Thread t = q.thread;
if (t != null) {
q.thread = null;
LockSupport.unpark(t);
}
WaitNode next = q.next;
if (next == null)
break;
q.next = null; // unlink to help gc
q = next;
}
break;
}
}
//① 調用了FutureTask中的done方法
done();
callable = null; // to reduce footprint
}
由set方法,調用finishCompletion,主要看finishCompletion的邏輯,我們只關注finishCompletion代碼的①處,這裡調用了done方法, 這樣我們來看done方法中的邏輯。
mFuture = new FutureTask在Future中調用了postResultIfNotInvoked,其實這裡將這段處理邏輯抽取到方法中去了,在android2.3即以前的源碼都是沒有抽取的,這也是使得現在的邏輯更加清晰。 ==java.util.concurrent.atomic.AtomicBoolean ( 在這個Boolean值的變化的時候不允許在之間插入,保持操作的原子性==) 由於在mWorker中的call和在mFuture的done方法都會調用postResult來更新UI,由於是線程操作,不能保證先後順序,所以需要使用AtomicBoolean來保持操作的原子性。其實在2.3上的代碼不是這樣處理的,2.3上將更新UI的操作都放在mFuture中的done方法中。(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); } } };
private void postResultIfNotInvoked(Result result) {
final boolean wasTaskInvoked = mTaskInvoked.get();
if (!wasTaskInvoked) {
postResult(result);
}
}
最後,我們來看postResult方法。
private Result postResult(Result result) {
@SuppressWarnings("unchecked")
Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult(this, result));
message.sendToTarget();
return result;
}
這裡就是我們非常熟悉的代碼了,使用Message發送消息給Handler來更新UI。 在AsyncTask中定義了一個InternalHandler,如果耗時操作執行完畢,就會執行finish(result.mData[0]),如果結果正在執行,則會onProgressUpdate來更新進度,這個onProgressUpdate正是我們前面說到的需要實現的更新進度的方法。
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;
}
}
}
AsyncTaskResult類的只是一個封裝
@SuppressWarnings({"RawUseOfParameterizedType"})
private static class AsyncTaskResult {
final AsyncTask mTask;
final Data[] mData;
AsyncTaskResult(AsyncTask task, Data... data) {
mTask = task;
mData = data;
}
}
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
//////耗時操作執行完畢,更新UI///////////
//onPostExecute運行在主線程
onPostExecute(result);
//////////////////////////////////////////
}
mStatus = Status.FINISHED;
}
這樣我們關於AsyncTask的流程終於走通了,為什麼onPreExecute和onPostExecute運行在主線程,而doingBackGround為什麼運行在子線程中,這個邏輯是不是就變得清晰了。上面貼了好多代碼,一直都是在分析代碼的意思,至於關於設計的思想感覺現在的自己還體悟不夠。
關於AsyncTask中executeOnExecutor中的sDefaultExecutor
項目中問題場景:
操作步驟>>>>>>>>>>>
- 設置安全中,選擇指紋。
- 解鎖方式選擇圖案。
- 在選擇您的圖案界面,點擊確定,需要三到五秒才能跳轉到下一界面。
問題分析:在設置解鎖方式為為圖案時,第二次繪制圖案後,Settings源碼中使用了AsyncTask來將一些比較耗時的驗證操作放在子線程中去處理(參看下面的部分代碼),由於android原生設計是使用
AsyncTask中的一個參數的方法,一個參數的方法采用的是默認的執行器,即串行執行器
==frameworks/base/core/java/com/android/internal/widget/LockPatternChecker.java==
public static AsyncTask verifyPattern(final LockPatternUtils utils,
final List pattern,
final long challenge,
final int userId,
final OnVerifyCallback callback) {
AsyncTask task = new AsyncTask() {
private int mThrottleTimeout;
@Override
protected byte[] doInBackground(Void... args) {
try {
return utils.verifyPattern(pattern, challenge, userId);
} catch (RequestThrottledException ex) {
mThrottleTimeout = ex.getTimeoutMs();
return null;
}
}
@Override
protected void onPostExecute(byte[] result) {
callback.onVerified(result, mThrottleTimeout);
}
};
////////////默認使用的串行的執行器//////////////
task.execute();
///////////////////////////////////////////////
return task;
}
public static final Executor SERIAL_EXECUTOR = new SerialExecutor(); private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
private static class SerialExecutor implements Executor {
final ArrayDeque mTasks = new ArrayDeque();
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);
}
}
}
我們發現SerialExecutor即是串行執行器,它的作用是保證任務執行的順序,也就是它可以保證提交的任務確實是按照先後順序執行的。它的內部有一個隊列用來保存所提交的任務,保證當前只運行一個,這樣就可以保證任務是完全按照順序執行的。如果發現異步任務還未執行,可能被我們發現SerialExecutor即是串行執行器順序的使用線程執行。因為應用中可能還有其他地方使用AsyncTask,所以到我們的AsyncTask也許會等待到其他任務都完成時才得以執行而不是調用executor()之後馬上執行。
如果executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,params)則不一樣。
/**
* An {@link Executor} that can be used to execute tasks in parallel.
*/
public static final Executor THREAD_POOL_EXECUTOR
= new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
API中的解釋:能夠並行的執行任務。THREAD_POOL_EXECUTOR是一個數量為corePoolSize的線程池,具體線程池的數量是依據CPU的核心來設置的,如果超過這個數量的線程個數就需要等待
SerialExecutor是按順序執行,THREAD_POOL_EXECUTOR則一定程度上能保證並行執行。
以上就是關於AsyncTask的全部內容,希望能對你有些幫助,貼了好多源碼,如果想真正弄清楚,還是得自己去閱讀閱讀源碼,整理這個也不容易,前前後後花了大概一個星期。
最後是AsyncTask的時序圖,畫的不太好,湊合看吧,O(∩_∩)O哈哈~

Java的進化? Kotlin初探與集成Android項目
介紹:Statically typed programming language for the JVM, Android and the browser. 100% i
Android編譯系統(二)-mm編譯單個模塊
因為Android的編譯系統不同於Linux Kernel的遞歸式的編譯系統,它的編譯系統是一種稱之為independent的模式,每個模塊基本獨立(它有可能依賴其他模塊
Android筆記之 網絡http通信
0、在認識HTTP前先認識URL 在我們認識HTTP之前,有必要先弄清楚URL的組成,例如: http://www.******.com/china/index.htm
Andorid獲取狀態欄高度
在應用開發中,有時我們需要用代碼計算布局的高度,可能需要減去狀態欄(status bar)的高度。狀態欄高度定義在Android系統尺寸資源中stat