android 結合源碼深入剖析AsyncTask機制原理
我們都知道,Android UI線程是不安全的,如果想要在子線程裡面進行UI操作,就需要直接Android的非同步消息處理機制,前面我寫了一篇從源碼層面分析了Android非同步消息Handler的處理機制。感興趣的可以去了解下。不過為了更方便我們在子線程中更新UI元素,Android1.5版本就引入了一個AsyncTask類,使用它就可以非常靈活方便地從子線程切換到UI線程。
一、基本用法
AsyncTask是一個抽象類,我們需要創建子類去繼承它,並且重寫一些方法。AsyncTask接受三個泛型的參數:
- Params:指定傳給任務執行時的參數的類型
- Progress:指定後台任務執行時將任務進度返回給UI線程的參數類型
- Result:指定任務完成後返回的結果類型
除了指定泛型參數,還需要根據重寫一些方法,常用的如下:
onPreExecute():這個方法在UI線程調用,用於在任務執行器那做一些初始化操作,如在界面上顯示載入進度 空間onInBackground:在onPreExecute()結束之後立刻在後台線程調用,用於耗時操作。在這個方法中可調用publishProgress方法返回任務的執行進度。onProgressUpdate:在doInBackground調用publishProgress後被調用,工作在UI線程onPostExecute:後台任務結束後被調用,工作在UI線程。
二、AsyncTask類源碼解析
AsyncTask.java源碼地址
源碼注釋大致翻譯一下:
AsyncTask可以輕鬆的正確使用UI線程,該類允許你執行後台操作並在UI線程更新結果,從而避免了無需使用Handler來操作線程AsyncTask是圍繞Thread與Handler而設計的輔助類,所以它並不是一個通用的線程框架。理想情況下,AsyncTask應該用於短操作(最多幾秒)。如果你的需求是在長時間保持線程運行,強烈建議您使用由
java.util.concurrent提供的各種API包,比如Executor、ThreadPoolExecutor或者FutureTask。一個非同步任務被定義為:在後台線程上運行,並在UI線程更新結果。一個非同步任務通常由三個類型:Params、Progress和Result。以及4個步驟:onPreExecute、doInBackground、onProgressUpdate、onPostExecute。用法:AsyncTask必須由子類實現後才能使用,它的子類至少重寫doInBackground()這個方法,並且通常也會重寫onPostExecute()這個方法
取消任務
在任何時候都可以通過調用cancel(boolean)來取消任務。調用此方法將導致isCancelled()方法的後續調用返回true。調用此方法後,在執行doInBackground(Object [])方法後,將調用onCancelled(object),而不是onPostExecute(Object)方法。為了儘可能快的取消任務,如果可能的話,你應該在調用doInBackground(Object[])之前檢查isCancelled()的返回值。線程規則,這個類必須遵循有關線程的一些規則才能正常使用,規則如下:
- 必須在UI線程上載入AsyncTask類,android4.1上自動完成
- 任務實例必須在UI線程上實例化
- execute()方法必須在主線程上調用
- 不要手動去調用onPreExecute()、onPostExecute()、doInBackground()、onProgressUpdate()方法。
- 這個任務只能執行一次(如果嘗試第二次執行,將會拋出異常)。
- 該任務只能執行一次(如果嘗試第二次執行,將拋出異常)。
內存的觀察AsyncTask。保證所有回調調用都是同步的,使得以下操作在沒有顯示同步情況下是安全的。
- 在構造函數或者onPreExecute設置成員變數,並且在doInBackground()方法中引用它們。
- 在doInBackground()設置成員欄位,並在onProgressUpdate()和onPostExecute()方法中引用他們。
執行順序。第一引入AsyncTask時,AsyncTasks是在單個後台線程串列執行的。在android1.6以後,這被更改為允許多個任務並行操作的線程池。從android 3.0開始,每個任務都是執行在一個獨立的線程上,這樣可以避免一些並行執行引起的常見的應用程序錯誤。如果你想要並行執行,可以使用THREAD_POOL_EXECUTOR來調用executeOnExecutor()方法。
(二)、AsyncTask的結構
AsyncTask的結構如下:
我們看到在AsyncTask有4個自定義類,一個枚舉類,一個靜態塊,然後才是這個類的具體變數和屬性,那我們就依次講解;
(三)、枚舉Status
代碼在AsyncTask.java 256行
- public enum Status {
- /**
- * Indicates that the task has not been executed yet.
- */
- PENDING,
- /**
- * Indicates that the task is running.
- */
- RUNNING,
- /**
- * Indicates that {@link AsyncTask#onPostExecute} has finished.
- */
- FINISHED,
- }
枚舉Status上的注釋翻譯一下就是:Status表示當前任務的狀態,每種狀態只能在任務的生命周期內設置一次。
所以任務有三種狀態
- PENDING:表示任務尚未執行的狀態
- RUNNING:表示任務正在執行
- FINISHED:任務已完成
(四)、私有的靜態類InternalHandler
代碼在AsyncTask.java 656行
- private static class InternalHandler extends Handler {
- public InternalHandler() {
- // 這個handler是關聯到主線程的
- 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;
- }
- }
- }
通過上面的代碼我們知道:
InternalHandler繼承自Handler,並且在它的構造函數裡面調用了Looper.getMainLooper(),所以我們知道這個Handler是關聯主線程的。重寫了handleMessage(Message)方法,其中這個Message的obj這個類型是AsyncTaskResult(AsyncTaskResult我將在下面講解),然後根據msg.what的來區別。我們知道這個Message只有兩個標示,一個是MESSAGE_POST_RESULT 是代表消息的結果,一個是MESSAGE_POST_PROGRESS代表要執行onProgressUpdate()方法。
通過這段代碼我們可以推測AsyncTask內部實現線程切換,即切換到主線程是通過Handler來實現的。
(五)、私有的靜態類AsyncTaskResult
代碼在AsyncTask.java 682行
- @SuppressWarnings({"RawUseOfParameterizedType"})
- private static class AsyncTaskResult<Data> {
- final AsyncTask mTask;
- final Data[] mData;
- AsyncTaskResult(AsyncTask task, Data... data) {
- mTask = task;
- mData = data;
- }
- }
通過類名,我們大概可以推測出這一個負責AsyncTask結果的類
AsyncTaskResult這個類 有兩個成員變數,一個是AsyncTask一個是泛型的數組。
- mTask參數:是為了AsyncTask是方便在handler的handlerMessage回調中方便調用AsyncTask的本身回調函數,比如onPostExecute()函數、onPreogressUpdata()函數,所以在AsyncTaskResult需要持有AsyncTask。
- mData參數:既然是代表結果,那麼肯定要有一個變數持有這個計算結果
(六)、私有靜態抽象類WorkerRunnable
代碼在AsyncTask.java 677行
- private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
- Params[] mParams;
- }
這個抽象類很簡答,首先是實現了Callable介面,然后里面有個變數
mParams,類型是泛型傳進來的數組
(七)、局部變數詳解
AsyncTask的局部變數如下:
- private static final String LOG_TAG = "AsyncTask";
- private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
- // We want at least 2 threads and at most 4 threads in the core pool,
- // preferring to have 1 less than the CPU count to avoid saturating
- // the CPU with background work
- private static final int CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4));
- private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
- 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);
- /**
- * An {@link Executor} that can be used to execute tasks in parallel.
- */
- public static final Executor THREAD_POOL_EXECUTOR;
- /**
- * An {@link Executor} that executes tasks one at a time in serial
- * order. This serialization is global to a particular process.
- */
- public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
- private static final int MESSAGE_POST_RESULT = 0x1;
- private static final int MESSAGE_POST_PROGRESS = 0x2;
- private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
- private static InternalHandler sHandler;
- private final WorkerRunnable<Params, Result> mWorker;
- private final FutureTask<Result> mFuture;
- private volatile Status mStatus = Status.PENDING;
- private final AtomicBoolean mCancelled = new AtomicBoolean();
- private final AtomicBoolean mTaskInvoked = new AtomicBoolean();
那我們就來一一解答
- String LOG_TAG = "AsyncTask":列印專用
- CPU_COUNT = Runtime.getRuntime().availableProcessors():獲取當前CPU的核心數
- CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4)):線程池的核心容量,通過代碼我們知道是一個大於等於2小於等於4的數
- MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1:線程池的最大容量是2倍的CPU核心數+1
- KEEP_ALIVE_SECONDS = 30:過剩的空閑線程的存活時間,一般是30秒
- sThreadFactory:線程工廠,通過new Thread來獲取新線程,裡面通過使用AtomicInteger原子整數保證超高並發下可以正常工作。
- sPoolWorkQueue:靜態阻塞式隊列,用來存放待執行的任務,初始容量:128個
- THREAD_POOL_EXECUTOR:線程池
- SERIAL_EXECUTOR = new SerialExecutor():靜態串列任務執行器,其內部實現了串列控制,循環的取出一個個任務交給上述的並發線程池去執行。
- MESSAGE_POST_RESULT = 0x1:消息類型,代表發送結果
- MESSAGE_POST_PROGRESS = 0x2:消息類型,代表進度
- sDefaultExecutor = SERIAL_EXECUTOR:默認任務執行器,被賦值為串列任務執行器,就是因為它,AsyncTask變成了串列的了。
- sHandler:靜態Handler,用來發送上面的兩種通知,採用UI線程的Looper來處理消息,這就是為什麼AnsyncTask可以在UI線程更新UI
- WorkerRunnable<Params, Result> mWorke:是一個實現Callback的抽象類,擴展了Callable多了一個Params參數。
- mFuture:FutureTask對象
- mStatus = Status.PENDING:任務的狀態默認為掛起,即等待執行,其類型標示為volatile
- mCancelled = new AtomicBoolean():原子布爾類型,支持高並發訪問,標示任務是否被取消
- mTaskInvoked = new AtomicBoolean():原子布爾類型,支持高並發訪問,標示任務是否被執行過
(八)、靜態代碼塊
代碼在AsyncTask.java 226行
- 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;
- }
通過上面的(七)、局部變數詳解,我們知道在靜態代碼塊中創建了一個線程池threadPoolExecutor,並設置了核心線程會超時關閉,最後並把這個線程池指向THREAD_POOL_EXECUTOR。
(九)、私有的靜態類SerialExecutor
代碼在AsyncTask.java 226行
- private static class SerialExecutor implements Executor {
- // 循環數組實現的雙向Queue,大小是2的倍數,默認是16,有隊頭和隊尾巴兩個下標
- final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
- // 正在運行runnable
- Runnable mActive;
- public synchronized void execute(final Runnable r) {
- // 添加到雙向隊列中去
- mTasks.offer(new Runnable() {
- public void run() {
- try {
- //執行run方法
- r.run();
- } finally {
- //無論執行結果如何都會取出下一個任務執行
- scheduleNext();
- }
- }
- });
- // 如果沒有活動的runnable,則從雙端隊列裡面取出一個runnable放到線程池中運行
- // 第一個請求任務過來的時候mActive是空的
- if (mActive == null) {
- //取出下一個任務來
- scheduleNext();
- }
- }
- protected synchronized void scheduleNext() {
- //從雙端隊列中取出一個任務
- if ((mActive = mTasks.poll()) != null) {
- //線線程池執行取出來的任務,真正的執行任務
- THREAD_POOL_EXECUTOR.execute(mActive);
- }
- }
- }
首先,注意SerialExecutor的execute是synchronized的,所以無論多個少任務調用execute()都是同步的。其次,SerialExecutor裡面一個ArrayDeque隊列,通過代碼我們知道,SerialExecutor是通過ArrayDeque來管理Runnable對象的。通過上面我們知道execute()是同步的,所以如果你有10個任務同時調用SerialExecutor的execute()方法,就會把10個Runnable先後放入到mTasks中去,可見mTasks緩存了將要執行的Runnable。再次1,如果我們第一個執行execute()方法時,會調用ArrayDeque的offer()方法將傳入的Runnable對象添加到隊列的尾部,然後判斷mActive是不是null,因為是第一次調用,此時mActive還沒有賦值,所以mActive等於null。所以此時mActive == null成立,所以會調用scheduleNext()方法。再次2,我們在調用scheduleNext()裡面,看到會調用mTasks.poll(),我們知道這是從隊列中取出頭部元素,然後把這個頭部元素賦值給mActive,然後讓THREAD_POOL_EXECUTOR這個線程池去執行這個mActive的Runnable對象。再次3,如果這時候有第二個任務入隊,但是此時mActive!=null,不會執行scheduleNext(),所以如果第一個任務比較耗時,後面的任務都會進入隊列等待。再次4,上面知道由於第二個任務入隊後,由於mActive!=null,所以不會執行scheduleNext(),那樣這樣後面的任務豈不是永遠得不到處理,當然不是,因為在offer()方法裡面傳入一個Runnable的匿名類,並且在此使用了finnally代碼,意味著無論發生什麼情況,這個finnally裡面的代碼一定會執行,而finnally代碼塊裡面就是調用了scheduleNext()方法,所以說每當一個任務執行完畢後,下一個任務才會執行。最後,SerialExecutor其實模仿的是單一線程池的效果,如果我們快速地啟動了很多任務,同一時刻只會有一個線程正在執行,其餘的均處於等待狀態。
PS:scheduleNext()方法是synchronized,所以也是同步的
重點補充:
在Android 3.0 之前是並沒有SerialExecutor這個類的,那個時候是直接在AsyncTask中構建一個sExecutor常量,並對線程池總大小,同一時刻能夠運行的線程數做了規定,代碼如下:
- private static final ThreadPoolExecutor sExecutor = new ThreadPoolExecutor(CORE_POOL_SIZE,
- MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, sWorkQueue, sThreadFactory);
三、AsyncTask類的構造函數
代碼如下:
- 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
- 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);
- }
- }
- };
- }
通過注釋我們知道,這個方法創建一個非同步任務,構造函數必須在UI線程調用
構造函數也比較簡單,主要就是給mWorker和mFuture初始化,其中WorkerRunnable實現了Callable介面,
在構造函數裡面調用了postResult(Result)和postResultIfNotInvoked(Result),那我們就來分別看下
1、postResult(Result)方法
- // doInBackground執行完畢,發送消息
- private Result postResult(Result result) {
- @SuppressWarnings("unchecked")
- // 獲取一個Message對象
- Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
- new AsyncTaskResult<Result>(this, result));
- // 發送給線程
- message.sendToTarget();
- return result;
- }
通過代碼我們知道
- 生成一個Message
- 把這個Message發送出
這裡面調用了 getHandler(),那我們來看下這個方法是怎麼寫的
2、getHandler()方法
- private static Handler getHandler() {
- synchronized (AsyncTask.class) {
- if (sHandler == null) {
- sHandler = new InternalHandler();
- }
- return sHandler;
- }
- }
我們看到返回的是InternalHandler對象,上面說過了InternalHandler其實是關聯主線程的,所以上面方法 message.sendToTarget(); 其實是把消息發送給主線程。
大家注意一下 這裡的Message的what值為MESSAGE_POST_RESULT,我們來看下InternalHandler遇到InternalHandler這種消息是怎麼處理的
- private static class InternalHandler extends Handler {
- ...
- 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;
- ...
- }
- }
- }
我們看到MESSAGE_POST_RESULT對應的是指是執行AsyncTask的finish(Result)方法,所以我們可以這樣說,無論AsyncTask是成功了還是失敗了,最後都會執行finish(Result)方法。那我們來看下finish(Result)方法裡面都幹了什麼?
2.1、finish(Result result) 方法
- private void finish(Result result) {
- if (isCancelled()) {
- // 如果消息取消了,執行onCancelled方法
- onCancelled(result);
- } else {
- // 如果消息沒有取消,則執行onPostExecute方法
- onPostExecute(result);
- }
- // 設置狀態值
- mStatus = Status.FINISHED;
- }
注釋寫的很清楚了,我這裡就不說明了,通過上面的代碼和finish方法的分析,我們知道無論成功還是失敗,最後一定會調用finish(Result)方法,所以最後狀態的值為FINISHED。
3、postResultIfNotInvoked(Result)方法
- private void postResultIfNotInvoked(Result result) {
- // 獲取mTaskInvoked的值
- final boolean wasTaskInvoked = mTaskInvoked.get();
- if (!wasTaskInvoked) {
- postResult(result);
- }
- }
通過上面代碼我們知道,如果mTaskInvoked不為true,則執行postResult,但是在mWorker初始化的時候為true,除非在沒有執行call方法時候,如果沒有執行call,說明這個非同步線程還沒有開始執行,這個時候mTaskInvoked為false。而這時候調用postResultIfNotInvoked則還是會執行postResult(Result),這樣保證了AsyncTask一定有返回值。
四、AsyncTask類核心方法解析
(一)、void onPreExecute()
- /**
- * Runs on the UI thread before {@link #doInBackground}.
- *
- * @see #onPostExecute
- * @see #doInBackground
- */
- // 在調用doInBackground()方法之前,跑在主線程上
- @MainThread
- protected void onPreExecute() {
- }
其實注釋很清楚了,在task任務開始執行的時候在主線程調用,在doInBackground(Params… params) 方法之前調用。
(二)、AsyncTask<Params, Progress, Result> onPreExecute() 方法
- @MainThread
- public final AsyncTask<Params, Progress, Result> execute(Params... params) {
- return executeOnExecutor(sDefaultExecutor, params);
- }
首先來翻譯一下注釋
- 使用指定的參數來執行任務,這個方法的返回值是this,也就是它自己,因為這樣設計的目的是可以保持對它的引用。
- 注意:它的調度模式是不同的,一種是單個後台線程,一種是通過線程池來實現,具體那種模式是根據android版本的不同而不同,當最開始引入AsyncTask的時候,AsyncTask是單個後台線程上串列執行,從Android DONUT 開始,模式變更為通過線程池多任務並行執行。在Android HONEYCOMB開始,又變回了在單個線程上執行,這樣可以避免並行執行的錯誤。如果你還是想並行執行,你可以使用executeOnExecutor()方法並且第一個參數是THREAD_POOL_EXECUTOR就可以了,不過,請注意有關使用警告。
- 必須在UI主線程上調用此方法。
通過代碼我們看到,它的內部其實是調用executeOnExecutor(Executor exec, Params... params)方法,只不過第一個參數傳入的是sDefaultExecutor,而sDefaultExecutor是SerialExecutor的對象。上面我們提到了SerialExecutor裡面利用ArrayDeque來實現串列的,所以我們可以推測出如果在executeOnExecutor(Executor exec, Params... params)方法裡面如果第一個參數是自定義的Executor,AsyncTask就可以實現並發執行。
(三)、executeOnExecutor(Executor exec, Params... params) 方法
- @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是先執行,並且在UI線程
- onPreExecute();
- // 設置參數
- mWorker.mParams = params;
- // 開啟了後台線程去計算,這是真正調用doInBackground的地方
- exec.execute(mFuture);
- // 接著會有onProgressUpdate會被調用,最後是onPostExecute
- return this;
- }
該方法首先是判斷mStatus狀態,如果是正在運行(RUNNING)或者已經結束(FINISHED),就會拋出異常。接著設置狀態為RUNNING,即運行,執行onPreExecute()方法,並把參數的值賦給mWorker.mParams於是Executor去執行execute的方法,學過Java多線程的都知道,這裡方法是開啟一個線程去執行mFuture的run()方法(由於mFuture用Callable構造,所以其實是執行的Callable的call()方法,而mWorker是Callable的是實現類,所以最終執行的是mWorker的call()方法)
PS:mFuture和mWorker都是在AsyncTask的構造方法中初始化過的。
主要是設置後台進度,onProgressUpdate會被調用
- @WorkerThread
- protected final void publishProgress(Progress... values) {
- if (!isCancelled()) {
- getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
- new AsyncTaskResult<Progress>(this, values)).sendToTarget();
- }
- }
這個方法內部實現很簡單
- 首先判斷 任務是否已經被取消,如果已經被取消了,則什麼也不做
- 如果任務沒有被取消,則通過InternalHandler發送一個what為MESSAGE_POST_PROGRESS的Message
這樣就進入了InternalHandler的handleMessage(Message)裡面了,而我們知道InternalHandler的Looper是Looper.getMainLooper(),所以處理Message是在主線程中,我們來看下代碼
- 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;
- }
- }
- }
通過代碼,我們看到如果what為MESSAGE_POST_PROGRESS,則會在主線程中調用onProgressUpdate(result.mData),這也就是為什麼我們平時在非同步線程調用publishProgress(Progress...)方法後,可以在主線程中的onProgressUpdate(rogress... values)接受數據了。
五、AsyncTask與Handler
AsyncTask:
- 優點:AsyncTask是一個輕量級的非同步任務處理類,輕量級體現在,使用方便,代碼簡潔,而且整個非同步任務的過程可以通過cancel()進行控制
- 缺點:不適用處理長時間的非同步任務,一般這個非同步任務的過程最好控制在幾秒以內,如果是長時間的非同步任務就需要考慮多線程的控制問題;當處理多個非同步任務時,UI更新變得困難。
Handler:
- 優點:代碼結構清晰,容易處理多個非同步任務
- 缺點:當有多個非同步任務時,由於要配合Thread或Runnable,代碼可能會稍顯冗餘。
總之,AsyncTask不失為一個非常好用的非同步任務處理類。不過我從事Android開發5年多了,很少會用到AsyncTask,一般非同步任務都是Handler。
※SpringMVC工程的web.xml以及其他配置文件
※較全Vim快捷鍵鍵點陣圖(入門到進階)
TAG:程序員小新人學習 |