Android Asynctask與Handler的比較,優缺點區別,Asynctask源碼

1  AsyncTask實現的原理,和適用的優缺點

AsyncTask,是android提供的輕量級的異步類,能夠直接繼承AsyncTask,在類中實現異步操做,提供接口反饋當前異步執行的程度(能夠經過接口實現UI進度更新),最後反饋執行的結果給UI主線程.php

使用的優勢:html

l  簡單,快捷java

l  過程可控android

使用的缺點:算法

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線程,剩下的排隊。

二、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);  
        }  
    }  
}


三、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;
        }
    }
}
相關文章
相關標籤/搜索