編輯:關於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首先,mWorker在構造方法中創建,它是一個匿名內部類,那WorkerRunnable是個什麼東西呢?() { public Result call() throws Exception { ..... } }; mFuture = new FutureTask (mWorker) { @Override protected void done() { ..... } }; }
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在FutureTask中的run方法,我們需要關注兩個地方,第一個,就是上面代碼片段的①處,這裡調用了mWorker中的call方法,這樣我們再回頭來看mWorker中的call方法。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); } }
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在mWorker中call方法中主要就是執行耗時操作,正是doInBackground方法,並且將執行的結果result返回回去,用postResult對doInBackground進行包裹則是為了運用Handler機制來更新UI。 接下來我們看FutureTask中run方法中的②處,調用了FutureTask自己的set方法。(this, result)); message.sendToTarget(); return result; }
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這裡就是我們非常熟悉的代碼了,使用Message發送消息給Handler來更新UI。 在AsyncTask中定義了一個InternalHandler,如果耗時操作執行完畢,就會執行finish(result.mData[0]),如果結果正在執行,則會onProgressUpdate來更新進度,這個onProgressUpdate正是我們前面說到的需要實現的更新進度的方法。(this, result)); message.sendToTarget(); return result; }
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 Listpattern, 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 ArrayDequemTasks = 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哈哈~
介紹:Statically typed programming language for the JVM, Android and the browser. 100% i
因為Android的編譯系統不同於Linux Kernel的遞歸式的編譯系統,它的編譯系統是一種稱之為independent的模式,每個模塊基本獨立(它有可能依賴其他模塊
0、在認識HTTP前先認識URL 在我們認識HTTP之前,有必要先弄清楚URL的組成,例如: http://www.******.com/china/index.htm
在應用開發中,有時我們需要用代碼計算布局的高度,可能需要減去狀態欄(status bar)的高度。狀態欄高度定義在Android系統尺寸資源中stat