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;
}
}
}
