Android的AsyncTask非同步任務淺析
Android的AsyncTask非同步任務淺析
實現原理
內部封裝了2個執行緒池+1個Handler(InternalHandler),1個執行緒池SerialExecutor任務排隊,一個執行緒池THREAD_POOL_EXECUTOR執行任務。
常用重寫的方法
- onPreExecute:執行在主執行緒中,可做UI更新,顯示進度條通知等。
- doInBackground:在子執行緒執行任務,接收的引數型別為AsyncTask第一個泛型,返回給onPostExecute的引數型別為AsyncTask第三個泛型。
- onProgressUpdate:執行在主執行緒中,doInBackground中呼叫publishProgress方法後即可回撥到該方法中,用於UI進度更新。接收的引數型別為AsyncTask第二個泛型。
- onPostExecute:執行在主執行緒中,doInBackground任務執行完畢後,就會回撥到該方法中。
- onCancelled:呼叫AsyncTask的cancel方法時,會回撥到該方法中,內部呼叫Thread的interrupt方法,告訴執行緒池要取消任務,Thread在合適時機取消任務。
public class MyTask extends AsyncTask<String, Double, Float> { @Override // 子執行緒執行任務 protected Float doInBackground(String... strings) { publishProgress(5D); return 1f; } @Override // 準備執行doInBackground任務時回撥 protected void onPreExecute() { super.onPreExecute(); } @Override // doInBackground任務執行結束後回撥,接收的引數為doInBackground返回的值 protected void onPostExecute(Float aFloat) { super.onPostExecute(aFloat); } @Override // doInBackground呼叫publishProgress會回撥到該方法中 protected void onProgressUpdate(Double... values) { super.onProgressUpdate(values); } @Override // 呼叫AsyncTask的任務關閉後回撥 protected void onCancelled() { super.onCancelled(); } }
注意事項
- Android4.1之前,AsyncTask類必須在主執行緒中載入。Android4.1之後,沒有了這個要求,ActivityThread的main方法中自動載入了AsyncTask。
- AsyncTask物件要在主執行緒建立,建立時,AsyncTask構造方法中,會拿到當前執行緒的Looper,傳給new的Handler例項,以保證Handler是在主執行緒中。
public AsyncTask(@Nullable Looper callbackLooper) { // 建立AsyncTask物件時,若不傳外部的Handler例項,會走到這個構造中 // 拿到當前執行緒的Looper,傳給new的Handler,則Handler在當前建立AsyncTask物件的執行緒中 // 因此,若要保證Handler執行環境在主執行緒,必須要在主執行緒中建立AsyncTask物件 mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper() ? getMainHandler() : new Handler(callbackLooper); ......省略無關程式碼 }
- AsyncTask物件的execute方法必須在主執行緒中呼叫。execute方法有@MainThread註解。
- Android3.0之前AsyncTask調execute方法是並行執行任務,3.0之後增加了SerialExecutor執行緒池,預設選擇該執行緒池序列執行任務,若想並行執行,則直接調executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, params)方法即可。
MyTask myTask = new MyTask(); // 預設在SerialExecutor執行緒池中序列執行 myTask.execute("1"); // 並行執行 myTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, "1");
- 一個AsyncTask物件,只能執行一次execute方法,第二次執行就會拋異常。
@MainThread // 主執行緒中執行的方法,預設選擇SerialExecutor執行緒池序列執行任務 public final AsyncTask<Params, Progress, Result> execute(Params... params) { return executeOnExecutor(sDefaultExecutor, params); } @MainThread// 主執行緒中執行的方法。外部也可直接調這個方法執行任務,自己傳入執行緒池選擇是序列還是並行。 public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec, Params... params) { // 一個AsyncTask物件,若多次執行execute,走到這裡,會判斷任務在執行中或已結束時,都將拋異常 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; }
- 記憶體洩漏問題。採用靜態的AsyncTask繼承類,若要引用外部,採用弱引用。
- 使用多個非同步操作並需要進行UI變更時,用AsyncTask會很複雜,替換Handler會更靈活。