AsyncTask 原始碼解析
為了不同環境下的使用,Android對Thread進行了包裝,產生了AsyncTask,HandleThread,IntentService。
1. AsyncTask
三個泛型: Params
用於初始化, Progress
用於設定進度, Result
返回的結果,如果沒有引數則設定為 Void
。
五個方法:
onPreExecute() doInbackground(Params) onProgressUpdate(Progress) onPostExecute() onCancelled()
簡單使用:
class DownloadTask extends AsyncTask<Void, Integer, Boolean> { @Override protected void onPreExecute() { progressDialog.show(); } @Override protected Boolean doInBackground(Void... params) { try { while (true) { int downloadPercent = doDownload(); publishProgress(downloadPercent); if (downloadPercent >= 100) { break; } } } catch (Exception e) { return false; } return true; } @Override protected void onProgressUpdate(Integer... values) { progressDialog.setMessage("當前下載進度:" + values[0] + "%"); } @Override protected void onPostExecute(Boolean result) { progressDialog.dismiss(); if (result) { Toast.makeText(context, "下載成功", Toast.LENGTH_SHORT).show(); } else { Toast.makeText(context, "下載失敗", Toast.LENGTH_SHORT).show(); } } }
兩個執行緒池:
- SerialExecutor :任務排隊
- THREAD_POOL_EXECUTOR:執行任務
注意點:
-
AsyncTask
的類載入必須在主執行緒中完成,因為AsyncTask
類中有靜態域sHandler
,用於切換主執行緒和子執行緒。sHnadler
必須獲取主執行緒的Looper
,所以sHandler
必須在主執行緒中建立。而靜態變數的建立在類載入的時候完成,所以AsyncTask
必須在主執行緒中載入。Android4.1之後系統自動完成這個操作。 -
AsyncTask物件建立和
execute
方法必須在主執行緒中呼叫嘗試在子執行緒中使用AsyncTask
-
一個
AsyncTask
只能被執行一次,不然會被報異常。檢視原始碼,在執行executor()
方法之後,首先會檢測AsyncTask的Status,如果 Status為RUNDING
或者FINISHED
則會丟擲異常。在檢測完Status
之後將其設定為RUNNING
。
public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,Params... params) { // 檢查狀態 if (mStatus != Status.PENDING) { switch (mStatus) { case RUNNING: throw new IllegalStateException("Cannot execute task:" + " the task is already running."); case FINISHED: throw new IllegalStateException("Cannot execute task:" + " the task has already been executed " + "(a task can be executed only once)"); } } mStatus = Status.RUNNING; onPreExecute(); mWorker.mParams = params; exec.execute(mFuture); return this; }
-
Android3.0
之後AsyncTask
任務由一個執行緒序列執行,如果是呼叫executeOnExecute則是並行執行任務。檢視原始碼
private static class SerialExecutor implements Executor { final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>(); Runnable mActive; // 執行 public synchronized void execute(final Runnable r) { mTasks.offer(new Runnable() { public void run() { try { r.run(); } finally { scheduleNext(); // 執行完成之後執行佇列中下一個任務 } } }); if (mActive == null) { scheduleNext(); } } protected synchronized void scheduleNext() { if ((mActive = mTasks.poll()) != null) { THREAD_POOL_EXECUTOR.execute(mActive);// 執行任務 } } }
初始狀態mActive為null,呼叫 scheduleNext()
,出佇列讓 THREAD_POOL_EXECUTOR
執行緒池去執行任務。 r.run()
執行完成之後執行 finaly{}
語句,呼叫下一個任務,依次繼續。
參考資料
《Android藝術探索》
android中handler的一些總結以及使用(三)之HandleThread的使用