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


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




免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM