【源碼解析】AsyncTask的用法與規則

引言

AsyncTask,相信你們已經很熟悉了。它的內部封裝了ThreadHandler,這讓咱們能夠將一些耗時操做放到AsyncTask,而且能將結果及時更新到UI上。AsyncTask主要用於短期耗時操做,長時間耗時操做不建議使用AsyncTask。下面經過Google官方的一個例子來認識AsyncTask的用法。併發

一個例子

private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
  protected void onPreExecute() {
        showProgress();
  }

  protected Long doInBackground(URL... urls) {
      int count = urls.length;
      long totalSize = 0;
      for (int i = 0; i < count; i++) {
          totalSize += Downloader.downloadFile(urls[i]);
          publishProgress((int) ((i / (float) count) * 100));
          // Escape early if cancel() is called
          if (isCancelled()) break;
      }
      return totalSize;
  }

  protected void onProgressUpdate(Integer... progress) {
      setProgressPercent(progress[0]);
  }

  protected void onPostExecute(Long result) {
      showDialog("Downloaded " + result + " bytes");
  }
 }

AsyncTask是一個抽象類,咱們要使用時必須自定義一個類繼承於它。AsyncTask的原型爲:ide

public abstract class AsyncTask<Params, Progress, Result> {
}

它接收三個泛型參數,分別表示參數類型、進度類型、結果類型測試

上述的例子中DownloadFilesTask接收參數類型爲URL類型,使用Integer類型表示任務進度,最終的任務結果是一個Long類型。this

注意:上面三個泛型類型不必定都得用一個明確的類型,對於沒有使用的類型,可使用Void類型代替。url

繼承AsyncTask至少須要重寫doInBackground方法,同時AsyncTask也提供了另外三個方法供咱們重寫,分別是onPreExecuteonProgressUpdateonPostExecute線程

  • onPreExecute方法。在任務開始執行以前執行,它運行在UI線程中。一般咱們能夠在這裏展現一個等待進度條。
  • doInBackground方法。貫穿整個耗時任務,它運行在子線程中。在這裏執行耗時操做。
  • onProgressUpdate方法。貫穿整個耗時任務,在publishProgress方法被調用後執行,它運行在UI線程中。一般用於展現整個任務的一個進度。
  • onProgressUpdate方法。在任務接收後調用,doInBackground的返回結果會透傳給onPostExecute的參數值,它運行在主線程中。一般咱們從這裏獲取任務執行完成後的結果數據。

AsyncTask的規則

  • AsyncTask類必須在UI線程加載。(在4.1系統版本以上會自動完成)
  • AsyncTask對象必須在UI線程建立,也就是說AsyncTask的構造方法必須在UI線程中調用。(通過測試AsyncTask對象能夠在子線程建立,只要保證execute方法在UI線程執行就OK的。可是沒有人會這樣作,由於畫蛇添足!!!)
  • execute方法必須在UI線程中調用。這樣作是保證onPreExecute方法運行在UI線程。
  • 不要主動調用onPreExecutedoInBackgroundonProgressUpdateonProgressUpdate方法。
  • 單線程下,AsyncTask對象的任務只能執行一次,不然會報運行時錯誤。

AsyncTask執行任務的規則

AsyncTask誕生之初,任務是在一個後臺線程中順序執行的。從Android 1.6開始,就變成了能夠在後臺線程中並行執行任務。而後,到了Android 3.0版本,又改爲了單線程順序執行,以此避免併發任務產生的錯誤行爲。code

爲了驗證上述結論,下面看一個Demo例子。orm

public class MainActivity extends Activity {
    public static final String TAG = "MyApplication";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        new MyTask("task1").execute();
        new MyTask("task2").execute();
        new MyTask("task3").execute();
        new MyTask("task4").execute();
        new MyTask("task5").execute();
        new MyTask("task6").execute();

    }

    private class MyTask extends AsyncTask<Void, Void, Void> {
        private String taskName;

        MyTask(String taskName) {
            this.taskName = taskName;
        }

        @Override
        protected Void doInBackground(Void... integers) {
            try {
                Thread.sleep(6000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return null;
        }

        @Override
        protected void onPostExecute(Void aVoid) {
            SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            Log.e(TAG, taskName + " finish at: " + df.format(new Date()));
        }
    }
}

這個例子比較簡單,就是在MainActivity啓動時,執行了六次MyTask,並將任務執行後的時間節點打印出來。對象

image.png

手機的系統版本是Android 8.0,從上面的Log信息能夠看出,AsyncTask的確是串行執行的。因爲現有測試機最低系統版本都是Android 4.1,已經很難找到Android 3.0如下的老古董機子了blog

相關文章
相關標籤/搜索