1 AsyncTask實現的原理,和適用的優缺點
AsyncTask,是android提供的輕量級的異步類,可以直接繼承AsyncTask,在類中實現異步操作,並提供接口反饋當前異步執行的程度(可以通過接口實現UI進度更新),最后反饋執行的結果給UI主線程.
使用的優點:
l 簡單,快捷
l 過程可控
使用的缺點:
l 在使用多個異步操作和並需要進行Ui變更時,就變得復雜起來.
2 Handler異步實現的原理和適用的優缺點
在Handler 異步實現時,涉及到 Handler, Looper, Message,Thread四個對象,實現異步的流程是主線程啟動Thread(子線程)àthread(子線程)運行並生成Message- àLooper獲取Message並傳遞給HandleràHandler逐個獲取Looper中的Message,並進行UI變更。
使用的優點:
l 結構清晰,功能定義明確
l 對於多個后台任務時,簡單,清晰
AsyncTask這個類感覺使用比較簡單,就是實現其中幾個方法,onPreExecute()方法是在任務剛開始運行時執行的一些初始化操作,比如初 始化一個進度條等等,然后就執行doInBackground()方法這里面主要放業務操作,比如查詢數據庫等,在這個方法執行的時候會調用 onProgressUpdate(),可以在這個方法中更新UI界面,最后是調用onPostExecute()方法,當得到業務結果后就可以在這個方 法中返回給UI線程,也可以關閉一些執行這個業務時開的一些資源。大家可以看得出AsyncTask這個類是一個泛型類,這個類的三個參數以此對應 doInBackground(String... params),onProgressUpdate(String... values),onPostExecute(String result)的參數,很形象的···如果不需要傳參和返回值,可以用Void代替。而doInBackground(String... params)方法的返回值也就是onPostExecute(String result)方法的參數值,因為doInBackground方法執行后返回的值是在onPostExecute(String result)中處理的。
用handler方式處理需要知道與handler相關的幾個組件,Looper和Queue,其實Looper的作用就是把handler發送的消息放 到Queue中,並把消息廣播給所有與這個Queue相關的handler,而Queue一般是主線程開啟的時候就給這個線程分配了一個,所以你要與UI 主線程通信必須用於這個Queue相關聯的handler對象才行,一般handler對象在那個線程中創建的就與那個線程的queue關聯,所以在UI 線程中創建的handler對象就與UI線程通訊,這樣我們就可以在子線程中發送消息給主線程,實現更新UI的功能。那主線程又是怎么處理子線程發送的消 息的呢?其實在生成handler對象的時候我們就要實現handler對象的handleMessage()方法這個方法就是主線程接受並處理子線程發 送過來的消息的方法,從而實現 更新UI線程的功能。
很多網友可能發現Android平台很多應用使用的都是AsyncTask,而並非Thread和Handler去更新UI,這里給大家說下他們到底有什 么區別,我們平時應該使用哪種解決方案。從Android 1.5開始系統將AsyncTask引入到android.os包中,過去在很早1.1和1.0 SDK時其實官方將其命名為UserTask,其內部是JDK 1.5開始新增的concurrent庫,做過J2EE的網友可能明白並發庫效率和強大性,比Java原始的Thread更靈活和強大,但對於輕量級的使 用更為占用系統資源。Thread是Java早期為實現多線程而設計的,比較簡單不支持concurrent中很多特性在同步和線程池類中需要自己去實現 很多的東西,對於分布式應用來說更需要自己寫調度代碼,而為了Android UI的刷新Google引入了Handler和Looper機制,它們均基於消息實現,有時可能消息隊列阻塞或其他原因無法准確的使用。
推薦大家使用AsyncTask代替Thread+Handler的方式,不僅調用上更為簡單,經過實測更可靠一些,Google在Browser中大量 使用了異步任務作為處理耗時的I/O操作,比如下載文件、讀寫數據庫等等,它們在本質上都離不開消息,但是AsyncTask相比Thread加 Handler更為可靠,更易於維護,但AsyncTask缺點也是有的比如一旦線程開啟即dobackground方法執行后無法給線程發送消息,僅能 通過預先設置好的標記來控制邏輯,當然可以通過線程的掛起等待標志位的改變來通訊,對於某些應用Thread和Handler以及Looper可能更靈 活。
本文主要講解下AsyncTask的使用以及Handler的應用
首先,我們得明確下一個概念,什么是UI線程。顧名思義,ui線程就是管理着用戶界面的那個線程!
android的ui線程操作並不是安全的,並且和用戶直接進行界面交互的操作都必須在ui線程中進行才可以。這種模式叫做單線程模式。
我們在單線程模式下編程一定要注意:不要阻塞ui線程、確保只在ui線程中訪問ui組件
當我們要執行一個復雜耗時的算法並且最終要將計算結果反映到ui上時,我們會發現,我們根本沒辦法同時保證上面的兩點要求;我們肯定會想到開啟一個新的線程,讓這個復雜耗時的任務到后台去執行,但是執行完畢了呢?我們發現,我們無法再與ui進行交互了。
為了解決這種情況,android為我們提供了很多辦法。
1)、handler和message機制:通過顯示的拋出、捕獲消息與ui進行交互;
2)、Activity.runOnUiThread(Runnable):如果當前線程為ui線程,則立即執行;否則,將參數中的線程操作放入到ui線程的事件隊列中,等待執行。
3)、View.post(Runnable):將操作放入到message隊列中,如果放入成功,該操作將會在ui線程中執行,並返回true,否則返回false
4)、View.postDelayed(Runnable, long)跟第三條基本一樣,只不過添加了一個延遲時間。
5)、android1.5以后為我們提供了一個工具類來搞定這個問題AsyncTask.
AsyncTask是抽象類,定義了三種泛型類型 Params,Progress,Result。
Params 啟動任務執行的輸入參數,比如HTTP請求的URL
Progress 后台任務執行的百分比。
Result 后台執行任務最終返回的結果,比如String
用程序調用,開發者需要做的就是實現這些方法。
1) 子類化AsyncTask
2) 實現AsyncTask中定義的下面一個或幾個方法
onPreExecute(),該方法將在執行實際的后台操作前被UI thread調用。可以在該方法中做一些准備工作,如在界面上顯示一個進度條。
doInBackground(Params…),將在onPreExecute 方法執行后馬上執行,該方法運行在后台線程中。這里將主要負責執行那些很耗時的后台計算工作。可以調用 publishProgress方法來更新實時的任務進度。該方法是抽象方法,子類必須實現。
onProgressUpdate(Progress…),在publishProgress方法被調用后,UI thread將調用這個方法從而在界面上展示任務的進展情況,例如通過一個進度條進行展示。
onPostExecute(Result),在doInBackground 執行完成后,onPostExecute 方法將被UI thread調用,后台的計算結果將通過該方法傳遞到UI thread.
為了正確的使用AsyncTask類,以下是幾條必須遵守的准則:
1) Task的實例必須在UI thread中創建
2) execute方法必須在UI thread中調用
3) 不要手動的調用onPreExecute(), onPostExecute(Result),doInBackground(Params…), onProgressUpdate(Progress…)這幾個方法
4) 該task只能被執行一次,否則多次調用時將會出現異常
下面介紹最本質的多線程:hanlder和message機制:
為何需要多線程:
在日常應用中,我們通常需要處理一些“后台,用戶不可見”的操作,例如說,我們需要下載一個音樂,要是你的應用必須等用戶下載完成之后才可以進行別的操 作,那肯定讓用戶非常的不爽。這時候,我們通常的做法是,讓這些操作去后台執行,然后等后台執行完畢之后,再給用戶彈出相應的提示信息。這時候,我們就需 要使用多線程機制,然后通過創建一個新的線程來執行這些操作。
明白了,實現需求,我們就准備着手實現了。但是,經過進一步的了解,我們悲劇的發現,android中的線程機制是,只能在UI線程中和用戶進行交互。當 我們創建了一個新線程,執行了一些后台操作,執行完成之后,我們想要給用戶彈出對話框以確認,但是卻悲劇的發現,我們根本無法返回UI主線程了。
(說明:何為UI線程:UI線程就是你當前看到的這些交互界面所屬的線程)。
這時候,我們如果想要實現這些功能,我們就需要一個android為我們提供的handler和message機制。
先講解下編程機制:
我們通常在UI線程中創建一個handler,handler相當於一個處理器,它主要負責處理和綁定到該handler的線程中的message。每一 個handler都必須關聯一個looper,並且兩者是一一對應的,注意,這點很重要哦!此外,looper負責從其內部的messageQueue中 拿出一個個的message給handler進行處理。因為我們這里handler是在UI線程中實現的,所以經過這么一個handler、 message機制,我們就可以回到UI線程中了。
何為handler:處理后台進程返回數據的工作人員。
何為message:后台進程返回的數據,里面可以存儲bundle等數據格式
何為messageQueue:是線程對應looper的一部分,負責存儲從后台進程中拋回的和當前handler綁定的message,是一個隊列。
何為looper:looper相當於一個messageQueue的管理人員,它會不停的循環的遍歷隊列,然后將符合條件的message一個個的拿出來交給handler進行處理。
注意,handler是在UI線程中聲明的,如果我們直接用類似代碼執行一個線程的話,實際上並沒有創建一個新的線程,因為handler已經跟默認的UI線程中的looper綁定了。
如果有興趣的話,可以去看下Handler的默認空構造函數便知道原因了,里面直接綁定了當前UI線程的looper。
下面給出一個比較簡單,並且實用的實例。
這2種方式都可以實現,但是他們的區別在哪里?優缺點各是什么?
(1)、AsyncTask是封裝好的線程池,比起Thread+Handler的方式,AsyncTask在操作UI線程上更方便,因為onPreExecute()、onPostExecute()及更新UI方法onProgressUpdate()均運行在主線程中,這樣就不用Handler發消息處理了;
(2)、我不太同意封裝好就會影響性能的說法,在我實際的運用中,真正的缺點來自於AsyncTask的全局線程池只有5個工作線程,也就是說,一個APP如果運用AsyncTask技術來執行線程,那么同一時間最多只能有5個線程同時運行,其他線程將被阻塞(注:不運用AsyncTask執行的線程,也就是自己new出來的線程不受此限制),所以AsyncTask不要用於多線程取網絡數據,因為很可能這樣會產生阻塞,從而降低效率。
三. 能否同時並發100+asynctask呢?
AsyncTask用的是線程池機制,容量是128,最多同時運行5個core線程,剩下的排隊。
2、AsyncTask是否異步
public class MainService extends Service{ private static Task task;//當前執行任務 private static Map<String, Activity> allActivitys = new HashMap<String, Activity>();//緩存activity集合 private static ExecutorService exec = Executors.newSingleThreadExecutor(); @Override public void onStart(Intent intent, int startId) { super.onStart(intent, startId); MainAsyncTask asyncTask = new MainAsyncTask(); //asyncTask.execute(task); //asyncTask.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, task); //asyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, task); //asyncTask.executeOnExecutor(Executors.newFixedThreadPool(2), task); asyncTask.executeOnExecutor(exec, task); } private final class MainAsyncTask extends AsyncTask<Object, Integer, Object>{ private Task task; @Override protected Object doInBackground(Object... params) { Object result = null; task = (Task)params[0]; switch (task.getTaskID()) { case Task.TASK_USER_LOGIN: try { Thread.sleep(3000); System.out.println("任務"+task.getTaskID()+" Thread id: "+Thread.currentThread().getId()); } catch (InterruptedException e) { e.printStackTrace(); } break; case 2: System.out.println("任務"+task.getTaskID()+" Thread id: "+Thread.currentThread().getId()); break; } return result; } @Override protected void onPostExecute(Object result) { super.onPostExecute(result); ActivityInterFace aif; switch (task.getTaskID()) { case Task.TASK_USER_LOGIN: aif = (ActivityInterFace)allActivitys.get("LoginActivity"); aif.refresh(1, result); break; case 2: aif = (ActivityInterFace)allActivitys.get("LoginActivity"); aif.refresh(2, result); break; default: break; } } } /** * 添加新任務 * @param task */ public static void addTask(Context context, Task task) { MainService.task = task; context.startService(new Intent("mainService")); } /** * 緩存activity * @param activity */ public static void addActivity(Activity activity) { String path = activity.getClass().getName(); String name = path.substring(path.lastIndexOf(".")+1); allActivitys.put(name, activity); } @Override public IBinder onBind(Intent intent) { return null; } }
當我執行兩次調用asyncTask.execute(task);時發現只有當第一次的任務完成后才執行下一下任務!!怎么回事?
AyncTask不是號稱異步線程池嗎?既然是線程池那么多任務執行時應該可以並發執行啊,至少兩個任務可以並發執
行,以前看過一個視頻,人家的就可以啊!糾結了一下午,通過查閱資料和自己的動手實驗終於把問題搞明白了。
原來在SDK3.0以前的版本執行asyncTask.execute(task);時的確是多線程並發執行的,線程池大小為5,最大可大
128個,google在3.0以后的版本中做了修改,將asyncTask.execute(task);修改為了順序執行,即只有當一個的實例
的任務完成后在執行下一個實例的任務。
那么怎么才能並發執行呢,很簡單,3.0后新增了一個方法executeOnExecutor(Executor
exec, Object... params),
該方法接受2個參數,第一個是Executor,第二個是任務參數。第一個是線程池實例,google為我們預定義了兩種:
第一種是AsyncTask.SERIAL_EXECUTOR,第二種是AsyncTask.THREAD_POOL_EXECUTOR,顧名思義,第一
種其實就像3.0以后的execute方法,是順序執行的。第二種就是3.0以前的execute方法,是可以並發執行的。我們直
接用asyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, task);就可以多任務並發執行了。
既然executeOnExecutor第一個參數是Executor,那么我們可以自定義Executor嗎?當然可以,Executor主要由四
種類型newCachedThreadPool,newFixedThreadPool,newScheduledThreadPool,newSingleThreadExecutor
(具體使用解析可以看我上一篇文章點擊打開鏈接),可是當我這樣使用
asyncTask.executeOnExecutor(Executors.newFixedThreadPool(1), task);或者
asyncTask.executeOnExecutor(Executors.newSingleThreadExecutor, task);並沒有像我想象的與
asyncTask.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, task);那樣是單線程順序執行,而是像
asyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, task);是多線程並發執行的,我不是
已經規定newFixedThreadPool的線程池數量是1或者是newSingleThreadExecutor單線程了么!怎么回事呢?原來程
序在每次調用asyncTask.executeOnExecutor(Executors.newFixedThreadPool(2), task)時會獲取一個新的Executor對
象,這個對象內的線程只執行對應的task,所以無論哪種情況每個task都有一個新的線程來執行,即並發執行。
知道原因就好辦了,我們定義個一全局靜態變量
private static ExecutorService exec = Executors.newSingleThreadExecutor();程序在每次調用
asyncTask.executeOnExecutor(exec, task);時是使用的同一個Executor,執行效果如下:
當Executor類型為:private static ExecutorService exec = Executors.newFixedThreadPool(2);只有兩個線程在執行
任務
當Executor類型為:private static ExecutorService exec = Executors.newSingleThreadExecutor();只有一個線程在執行任務
package com.example.ztestandroid; import java.util.Calendar; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import android.app.Activity; import android.os.AsyncTask; import android.os.Bundle; import com.example.ztestandroid.bean.Task; public class MainActivity extends Activity { private static ExecutorService exec = Executors.newSingleThreadExecutor(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); System.out.println("start time: "+Calendar.SECOND); for (int i = 1; i < 10; i++) { int count = i%2==0?1:2; Task task = new Task(count, "task "+i); MainAsyncTask asyncTask = new MainAsyncTask(); /* * 順序執行,AsyncTask里面有5個核心線程,最大128個 * 01-14 11:30:47.000: I/System.out(17418): start time: 13 01-14 11:30:47.000: I/System.out(17418): end time: 13 01-14 11:30:47.000: I/System.out(17418): 任務2 task 1 Thread id: 840 seconds: 1421206247008 01-14 11:30:50.020: I/System.out(17418): 任務1 task 2 Thread id: 841 seconds: 1421206250028 01-14 11:30:50.025: I/System.out(17418): 任務2 task 3 Thread id: 842 seconds: 1421206250033 01-14 11:30:53.030: I/System.out(17418): 任務1 task 4 Thread id: 843 seconds: 1421206253037 01-14 11:30:53.040: I/System.out(17418): 任務2 task 5 Thread id: 844 seconds: 1421206253047 01-14 11:30:56.050: I/System.out(17418): 任務1 task 6 Thread id: 844 seconds: 1421206256053 01-14 11:30:56.050: I/System.out(17418): 任務2 task 7 Thread id: 844 seconds: 1421206256055 01-14 11:30:59.050: I/System.out(17418): 任務1 task 8 Thread id: 844 seconds: 1421206259057 01-14 11:30:59.050: I/System.out(17418): 任務2 task 9 Thread id: 844 seconds: 1421206259058 */ // asyncTask.execute(task); // 和asyncTask.execute(task)執行結果相同,順序執行。 // asyncTask.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, task); /* * 可以看出是異步執行,線程池里面最多有5個線程 * 01-14 11:43:14.115: I/System.out(18208): start time: 13 01-14 11:43:14.115: I/System.out(18208): end time: 13 01-14 11:43:14.115: I/System.out(18208): 任務2 task 1 Thread id: 880 seconds: 1421206994121 01-14 11:43:14.115: I/System.out(18208): 任務2 task 3 Thread id: 877 seconds: 1421206994122 01-14 11:43:14.115: I/System.out(18208): 任務2 task 5 Thread id: 876 seconds: 1421206994122 01-14 11:43:14.115: I/System.out(18208): 任務2 task 7 Thread id: 877 seconds: 1421206994123 01-14 11:43:14.115: I/System.out(18208): 任務2 task 9 Thread id: 877 seconds: 1421206994123 01-14 11:43:17.115: I/System.out(18208): 任務1 task 2 Thread id: 880 seconds: 1421206997122 01-14 11:43:17.115: I/System.out(18208): 任務1 task 6 Thread id: 878 seconds: 1421206997123 01-14 11:43:17.115: I/System.out(18208): 任務1 task 8 Thread id: 876 seconds: 1421206997123 01-14 11:43:17.115: I/System.out(18208): 任務1 task 4 Thread id: 879 seconds: 1421206997123 */ asyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, task); /* * 異步執行 * 01-14 11:28:06.915: I/System.out(17143): start time: 13 01-14 11:28:06.915: I/System.out(17143): 任務2 task 1 Thread id: 837 seconds: 1421206086924 01-14 11:28:06.920: I/System.out(17143): 任務2 task 3 Thread id: 839 seconds: 1421206086925 01-14 11:28:06.920: I/System.out(17143): 任務2 task 5 Thread id: 841 seconds: 1421206086926 01-14 11:28:06.920: I/System.out(17143): 任務2 task 7 Thread id: 843 seconds: 1421206086926 01-14 11:28:06.920: I/System.out(17143): end time: 13 01-14 11:28:06.920: I/System.out(17143): 任務2 task 9 Thread id: 845 seconds: 1421206086927 01-14 11:28:09.925: I/System.out(17143): 任務1 task 2 Thread id: 838 seconds: 1421206089926 01-14 11:28:09.925: I/System.out(17143): 任務1 task 4 Thread id: 840 seconds: 1421206089927 01-14 11:28:09.925: I/System.out(17143): 任務1 task 6 Thread id: 842 seconds: 1421206089927 01-14 11:28:09.925: I/System.out(17143): 任務1 task 8 Thread id: 844 seconds: 1421206089927 */ // asyncTask.executeOnExecutor(Executors.newFixedThreadPool(2), task); /* * 執行結果: * 任務1 task 2 Thread id: 816 seconds: 1421205791881 任務2 task 3 Thread id: 816 seconds: 1421205791882 任務1 task 4 Thread id: 816 seconds: 1421205794883 任務2 task 5 Thread id: 816 seconds: 1421205794883 任務1 task 6 Thread id: 816 seconds: 1421205797884 任務2 task 7 Thread id: 816 seconds: 1421205797885 任務1 task 8 Thread id: 816 seconds: 1421205800886 任務2 task 9 Thread id: 816 seconds: 1421205800887 */ // asyncTask.executeOnExecutor(exec, task); } System.out.println("end time: "+Calendar.SECOND); } private final class MainAsyncTask extends AsyncTask<Object, Integer, Object>{ private Task task; @Override protected Object doInBackground(Object... params) { Object result = null; task = (Task)params[0]; switch (task.getTaskID()) { case Task.TASK_USER_LOGIN: try { Thread.sleep(3000); System.out.println("任務"+task.getTaskID()+" "+ task.getTask()+" Thread id: "+Thread.currentThread().getId()+" seconds: "+System.currentTimeMillis()); } catch (InterruptedException e) { e.printStackTrace(); } break; case 2: System.out.println("任務"+task.getTaskID()+" "+ task.getTask()+" Thread id: "+Thread.currentThread().getId()+" seconds: "+System.currentTimeMillis()); break; } return result; } @Override protected void onPostExecute(Object result) { super.onPostExecute(result); } } }
3、AsyncTask源碼分析
public abstract class AsyncTask { private static final String LOG_TAG = AsyncTask; //獲取當前的cpu核心數 private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors(); //線程池核心容量 private static final int CORE_POOL_SIZE = CPU_COUNT + 1; //線程池最大容量 private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1; //過剩的空閑線程的存活時間 private static final int KEEP_ALIVE = 1; //ThreadFactory 線程工廠,通過工廠方法newThread來獲取新線程 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()); } }; //靜態阻塞式隊列,用來存放待執行的任務,初始容量:128個 private static final BlockingQueue sPoolWorkQueue = new LinkedBlockingQueue(128); /** * 靜態並發線程池,可以用來並行執行任務,盡管從3.0開始,AsyncTask默認是串行執行任務 * 但是我們仍然能構造出並行的AsyncTask */ public static final Executor THREAD_POOL_EXECUTOR = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory); /** * 靜態串行任務執行器,其內部實現了串行控制, * 循環的取出一個個任務交給上述的並發線程池去執行 */ public static final Executor SERIAL_EXECUTOR = new SerialExecutor(); //消息類型:發送結果 private static final int MESSAGE_POST_RESULT = 0x1; //消息類型:更新進度 private static final int MESSAGE_POST_PROGRESS = 0x2; /**靜態Handler,用來發送上述兩種通知,采用UI線程的Looper來處理消息 * 這就是為什么AsyncTask必須在UI線程調用,因為子線程 * 默認沒有Looper無法創建下面的Handler,程序會直接Crash */ private static final InternalHandler sHandler = new InternalHandler(); //默認任務執行器,被賦值為串行任務執行器,就是它,AsyncTask變成串行的了 private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR; //如下兩個變量我們先不要深究,不影響我們對整體邏輯的理解 private final WorkerRunnable mWorker; private final FutureTask mFuture; //任務的狀態 默認為掛起,即等待執行,其類型標識為易變的(volatile) private volatile Status mStatus = Status.PENDING; //原子布爾型,支持高並發訪問,標識任務是否被取消 private final AtomicBoolean mCancelled = new AtomicBoolean(); //原子布爾型,支持高並發訪問,標識任務是否被執行過 private final AtomicBoolean mTaskInvoked = new AtomicBoolean(); /*串行執行器的實現,我們要好好看看,它是怎么把並行轉為串行的 *目前我們需要知道,asyncTask.execute(Params ...)實際上會調用 *SerialExecutor的execute方法,這一點后面再說明。也就是說:當你的asyncTask執行的時候, *首先你的task會被加入到任務隊列,然后排隊,一個個執行 */ private static class SerialExecutor implements Executor { //線性雙向隊列,用來存儲所有的AsyncTask任務 final ArrayDeque mTasks = new ArrayDeque(); //當前正在執行的AsyncTask任務 Runnable mActive; public synchronized void execute(final Runnable r) { //將新的AsyncTask任務加入到雙向隊列中 mTasks.offer(new Runnable() { public void run() { try { //執行AsyncTask任務 r.run(); } finally { //當前AsyncTask任務執行完畢后,進行下一輪執行,如果還有未執行任務的話 //這一點很明顯體現了AsyncTask是串行執行任務的,總是一個任務執行完畢才會執行下一個任務 scheduleNext(); } } }); //如果當前沒有任務在執行,直接進入執行邏輯 if (mActive == null) { scheduleNext(); } } protected synchronized void scheduleNext() { //從任務隊列中取出隊列頭部的任務,如果有就交給並發線程池去執行 if ((mActive = mTasks.poll()) != null) { THREAD_POOL_EXECUTOR.execute(mActive); } } } /** * 任務的三種狀態 */ public enum Status { /** * 任務等待執行 */ PENDING, /** * 任務正在執行 */ RUNNING, /** * 任務已經執行結束 */ FINISHED, } /** 隱藏API:在UI線程中調用,用來初始化Handler */ public static void init() { sHandler.getLooper(); } /** 隱藏API:為AsyncTask設置默認執行器 */ public static void setDefaultExecutor(Executor exec) { sDefaultExecutor = exec; } /** * Creates a new asynchronous task. This constructor must be invoked on the UI thread. */ public AsyncTask() { mWorker = new WorkerRunnable() { public Result call() throws Exception { mTaskInvoked.set(true); Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); //noinspection unchecked return postResult(doInBackground(mParams)); } }; mFuture = new FutureTask(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); } } //doInBackground執行完畢,發送消息 private Result postResult(Result result) { @SuppressWarnings(unchecked) Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT, new AsyncTaskResult(this, result)); message.sendToTarget(); return result; } /** * 返回任務的狀態 */ public final Status getStatus() { return mStatus; } /** * 這個方法是我們必須要重寫的,用來做后台計算 * 所在線程:后台線程 */ protected abstract Result doInBackground(Params... params); /** * 在doInBackground之前調用,用來做初始化工作 * 所在線程:UI線程 */ protected void onPreExecute() { } /** * 在doInBackground之后調用,用來接受后台計算結果更新UI * 所在線程:UI線程 */ protected void onPostExecute(Result result) { } /** * Runs on the UI thread after {@link #publishProgress} is invoked. /** * 在publishProgress之后調用,用來更新計算進度 * 所在線程:UI線程 */ protected void onProgressUpdate(Progress... values) { } /** * cancel被調用並且doInBackground執行結束,會調用onCancelled,表示任務被取消 * 這個時候onPostExecute不會再被調用,二者是互斥的,分別表示任務取消和任務執行完成 * 所在線程:UI線程 */ @SuppressWarnings({UnusedParameters}) protected void onCancelled(Result result) { onCancelled(); } protected void onCancelled() { } public final boolean isCancelled() { return mCancelled.get(); } public final boolean cancel(boolean mayInterruptIfRunning) { mCancelled.set(true); return mFuture.cancel(mayInterruptIfRunning); } public final Result get() throws InterruptedException, ExecutionException { return mFuture.get(); } public final Result get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { return mFuture.get(timeout, unit); } /** * 這個方法如何執行和系統版本有關,在AsyncTask的使用規則里已經說明,如果你真的想使用並行AsyncTask, * 也是可以的,只要稍作修改 * 必須在UI線程調用此方法 */ public final AsyncTask execute(Params... params) { //串行執行 return executeOnExecutor(sDefaultExecutor, params); //如果我們想並行執行,這樣改就行了,當然這個方法我們沒法改 //return executeOnExecutor(THREAD_POOL_EXECUTOR, params); } /** * 通過這個方法我們可以自定義AsyncTask的執行方式,串行or並行,甚至可以采用自己的Executor * 為了實現並行,我們可以在外部這么用AsyncTask: * asyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, Params... params); * 必須在UI線程調用此方法 */ public final AsyncTask 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會最先執行 onPreExecute(); mWorker.mParams = params; //然后后台計算#doInBackground才真正開始 exec.execute(mFuture); //接着會有#onProgressUpdate被調用,最后是#onPostExecute return this; } /** * 這是AsyncTask提供的一個靜態方法,方便我們直接執行一個runnable */ public static void execute(Runnable runnable) { sDefaultExecutor.execute(runnable); } /** * 打印后台計算進度,onProgressUpdate會被調用 */ protected final void publishProgress(Progress... values) { if (!isCancelled()) { sHandler.obtainMessage(MESSAGE_POST_PROGRESS, new AsyncTaskResult(this, values)).sendToTarget(); } } //任務結束的時候會進行判斷,如果任務沒有被取消,則onPostExecute會被調用 private void finish(Result result) { if (isCancelled()) { onCancelled(result); } else { onPostExecute(result); } mStatus = Status.FINISHED; } //AsyncTask內部Handler,用來發送后台計算進度更新消息和計算完成消息 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; } } } private static abstract class WorkerRunnable implements Callable { Params[] mParams; } @SuppressWarnings({RawUseOfParameterizedType}) private static class AsyncTaskResult { final AsyncTask mTask; final Data[] mData; AsyncTaskResult(AsyncTask task, Data... data) { mTask = task; mData = data; } } }