Android的AsyncTask異步任務淺析

Android的AsyncTask異步任務淺析

實現原理

內部封裝了2個線程池+1個Handler(InternalHandler),1個線程池SerialExecutor任務排隊,一個線程池THREAD_POOL_EXECUTOR執行任務。bash

經常使用重寫的方法

  • 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();
    }
}
複製代碼

注意事項

  1. Android4.1以前,AsyncTask類必須在主線程中加載。Android4.1以後,沒有了這個要求,ActivityThread的main方法中自動加載了AsyncTask。
  2. 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);
            
        ......省略無關代碼
    }
複製代碼
  1. AsyncTask對象的execute方法必須在主線程中調用。execute方法有@MainThread註解。
  2. 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");
複製代碼
  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;
}
複製代碼
  1. 內存泄漏問題。採用靜態的AsyncTask繼承類,若要引用外部,採用弱引用。
  2. 使用多個異步操做並須要進行UI變動時,用AsyncTask會很複雜,替換Handler會更靈活。
相關文章
相關標籤/搜索