Android 多線程:AsyncTask理解和使用總結

AsyncTask目錄.png

一、AsyncTask介紹

1.1 作用:

輕量級的異步類,同時方便在子線程更新UI。

1.2 原理:

封裝了Handler和兩個線程池。AsyncTask的源碼鏈接

  1. 線程池THREAD_POOL_EXECUTOR:通過ThreadFactory和一些參數實例化線程池THREAD_POOL_EXECUTOR用于執(zhí)行任務。
  2. 線程池SERIAL_EXECUTOR:內部類SerialExecutor實現Executor也是一個線程池,實例化對象SERIAL_EXECUTOR執(zhí)行SerialExecutor定義的execute方法來串行(一個一個按順序)排隊任務并使用THREAD_POOL_EXECUTOR來執(zhí)行任務
  3. AsyncTask創(chuàng)建時會實例化一個WorkerRunnable對象mWorker和一個FutureTask對象mFuture。FutureTask是一個并發(fā)類,充當Runnable的作用。AsyncTask執(zhí)行任務時把mFuture作為排隊線程池SerialExecutor的execute(final Runnable r)的參數傳遞,接著會串行排隊并使用工作線程來處理實際任務。
  4. mFuture對象創(chuàng)建時把mWorker對象作為參數傳遞,在mFuture在執(zhí)行任務run()時會調用mWorker的call()方法,因此call()方法是在線程池中進行的。
  5. 主線程的Handler:然后call()方法里面接著調用result = doInBackground(mParams);并返回Result對象,這個過程中任務被取消會catch跳出設置AsyncTask結束。call()方法最后postResult(result);獲取主線程的Handler發(fā)送消息并根據消息類型判定更新UI或者結束AsyncTask。
    具體參考:源碼解析Android中AsyncTask的工作原理

1.3 參數以及核心函數

AsyncTask是一個泛型類,在android.os包下

AsyncTask類.png

泛型內三個參數定義的是我們需要的數據的類型,如果不需要傳遞參數,可以用Void來代替,以下是具體含義:

  • Params:參數的類型;
  • Progress:后臺任務的執(zhí)行進度類型;
  • Result:后臺任務返回結果的類型。
    AsyncTask還提供了4個核心方法:
  1. protected void onPreExecute():在主線程執(zhí)行,異步任務執(zhí)行前調用做準備工作;
  2. protected abstract Result doInBackground(Params... var1):在線程池中執(zhí)行,用于執(zhí)行異步任務。Params表示異步任務輸入參數,可以在此方法中通過publishProgress方法來更新任務進度,publishProgress方法又調用onProgressUpdate方法實現主線程進度更新。這個方法返回ResultonPostExecute方法。
  3. protected void onProgressUpdate(Progress... values):在主線程執(zhí)行,后臺任務執(zhí)行進度發(fā)生變化會調用此方法。
  4. protected void onPostExecute(Result result):在主線程執(zhí)行,異步任務執(zhí)行后調用,result參數是由doInBackground返回的。

這四個方法執(zhí)行的順序為:onPreExecute(準備)-->doInBackground(后臺異步)-->onPostExecute(結果處理)
還有一個有用的方法:protected void onCancelled():當異步任務取消時調用,而這時候onPostExecute不會被調用。

二、AsyncTask使用

2.1 AsyncTask使用示例:

(1) 創(chuàng)建Activity,布局兩個按鈕用來開始和取消AsyncTask,一個TextView來顯示狀態(tài)。

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">

    <Button
        android:id="@+id/btn_download"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="開始下載"/>

    <Button
        android:id="@+id/btn_cancel"
        android:layout_below="@id/btn_download"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="取消下載"/>

    <TextView
        android:id="@+id/tv_statue"
        android:layout_below="@id/btn_cancel"
        android:textSize="15sp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

</RelativeLayout>

(2) 創(chuàng)建內部類自定義MyAsyncTask繼承AsyncTask,重寫四個主要方法:

  //第一個參數:Params參數類型:String類型 
  //第二個參數:Progress執(zhí)行進度類型:Object類型 
  //第三個參數:Result參數類型:Long類型
  private class MyAsyncTask extends AsyncTask<String,Object,Long>{
  ...
  @Override
  protected void onPreExecute() {...}

  @Override
  protected Long doInBackground(String... strings) {...}

  @Override  
  protected void onProgressUpdate(Object... values) {...}

   @Override
   protected void onPostExecute(Long aLong) {...}

  @Override //任務取消調用
  protected void onCancelled() {...}

(3)開始按鈕調用創(chuàng)建MyAsyncTask并執(zhí)行downloadTask.execute(urls)傳入參數。

mDownButton.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        String[] urls = {
                "http://www.itdecent.cn/p/d3984e7e204f",
                "http://www.itdecent.cn/p/8e3cfb87f35e",
                "http://www.itdecent.cn/p/4fbc2ea2e02b"
        };
        downloadTask = new MyAsyncTask();
        // 這里的url也可以分成一個一個參數傳遞
        downloadTask.execute(urls);
    }
});

(4) 取消按鈕調用downloadTask.cancel(true)停止MyAsyncTask。

//取消按鈕點擊事件
downloadTask.cancel(true);

(5) doInBackground(String... strings)方法循環(huán)執(zhí)行下載任務并返回result,是自己定義的二維數組,第一個是字節(jié)數,第二個是文章標題。

protected Long doInBackground(String... strings) {
    long totalByte = 0;
    for (String url:strings){
        // downloadFile方法只是一個簡單的下載字節(jié)流
        // 返回的Object[] result是二維數組,一個是下載的字節(jié)數,一個是標題
        Object[] result = downloadFile(url);
        int byteCount = (int) result[0];
        totalByte += byteCount;
        //傳遞進度
        publishProgress(result);
        // 異步任務調用取消則跳出for循環(huán)
        if(isCancelled()){
            break;
        }
    }
    return totalByte;
}

(6) 然后使用publishProgress(result);把數據傳遞給onProgressUpdate(Object... values)方法來更新UI,這個方法已經切換到了主線程,所以可以更新UI。AsyncTask完成后onPostExecute(Long aLong)方法自動調用再次來更新狀態(tài)。

  @Override
  protected void onPostExecute(Long aLong) {...}

看一下效果,源碼我會在后面放出,取消下載請自行測試。


AsyncTaskDemo.gif

2.2 AsyncTask使用注意:

  1. AsyncTask的類必須在主線程加載。
  2. AsyncTask的對象必須在主線程創(chuàng)建。
  3. execute方法必須在UI線程調用。
  4. 一個AsyncTask對象只能執(zhí)行一次,即只能調用一次execute方法,否則報運行時異常。
  5. 在Android1.6之前,AsyncTask是串行執(zhí)行任務的,Android1.6的時候AsyncTask開始使用線程池處理并行任務,但是從Android3.0開始,為了避免AsyncTask所帶來的并發(fā)錯誤,AsyncTask又采用一個線程串行執(zhí)行任務。盡管如此,在Android3.0以及后續(xù)的版本中,我們仍然可以通過AsyncTask的executeOnExecutor方法來并行地執(zhí)行任務。

三、AsyncTask優(yōu)點和缺點

3.1 優(yōu)點:

  1. 簡單快捷,使用方便。
  2. UI更新及時,過程可控。

3.2 缺點:

多個異步操作需要更新UI時,就變得麻煩起來。

3.3 其它問題:

參考文章:AsyncTask的缺陷和問題

目錄文章:
Android多線程:理解和簡單使用總結

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容