Android異步任務處理


Android異步任務處理

 

Android主線程(UI線程)不准執行異步任務,以免阻塞主線程。所以異步任務一定是在工作線程中完成,然后,通知主線程,進行返回結果,刷新UI等操作。

 

1、使用handler

使用handler可以很方便的進行主線程與工作線程的交互,當在線程里創建handler時,handler會自動綁定當前線程

重寫@Overried handlerMessage(),可以處理Message。

/**

*

*

*/

@Override

        public void handleMessage(@NonNull Message msg) {

//根據msg.what執行相應命令(不設置,默認為0),msg.obj攜帶結果信息           

switch (msg.what){

                case 0:

                …執行相應操作

 break;

                default:

            }

        }

 

 

常見的做法是在主線程中創建handler,在工作線程中處理完異步任務后發送Message,主線程重寫handlerMessage()里處理返回結果。

 

使用handler進行異步處理時,容易產生內存泄漏問題,固然可以通過將handler設置為靜態內部類,解決這個問題,但是將handler設置為靜態內部類后就無法引用內部成員變量。內存泄漏原因是activity要銷毀時,消息隊列里消息沒處理完,Message Queue默認引用handler,handler默認引用activity。

 

所以推薦的做法是:在onDestory()階段,清空消息隊列,取消handler引用。

 

protected void onDestroy() {

        super.onDestroy();

        if (mHandler != null) {

            mHandler.removeCallbacksAndMessages(null);

            mHandler = null;

        }

     }

(參考資料)

https://juejin.im/post/5a692377518825734e3e71ab

 

 

2、使用IntentService(異步任務處理服務)

使用IntentService,IntentService其實是封裝了service和handler的類,所以和上述類似,它處理消息是在@Overried

onHandleIntent()

根據傳入的intent執行相應的異步處理

IntentService其內部維護一個消息隊列,根據傳入的intent的時間,先來先服務。前一項服務沒處理完,后一項服務不會開始。

官網推薦的IntentService與Activity通信的方式是localBroadcast。

相比handler,其主要優點在於可以在后台執行,不受Activity生命周期影響。(只能通過startActivity()啟動IntentService,可以像普通service一樣綁定activity,通過Binder通信)

如果說消息隊列里沒消息了,那么service會暫停,內存不夠的情況下有可能被系統殺死。

 

3、使用handlerThread

聽名字就可以猜出來,一個繼承了Thread的handler處理類,其內部維護一個消息隊列,重寫@Overried handlerMessage()處理消息,對應於主線程。

一些情況下,我們需要工作線程處理消息,那么我們就創建一個handlerThread,根據傳入消息,執行異步任務。

 

比較好的理解方式:主線程可以有個handleMessage,我工作線程也想有個,但是新建一個Thread,設置Looper什么的太麻煩,於是新建一個HandlerThread,一些准備工作都做好了,像主線程一樣創建handler綁定線程,重寫@Overried handlerMessage()處理消息就OK了!

 

其實創建一個Hhread,手動引用創建一個Looper的效果和創建HandlerThread效果一樣

 

需要注意:為了防止內存泄漏,要像在主線程里的handler一樣,在onDestory()階段,

清空消息隊列,取消handler引用。

/**

  *

  *   workHandler: 綁定工作線程的handler

  *   mHandler:綁定主線程的handler

  */

protected void onDestroy() {

        super.onDestroy();

        if (workHandler != null) {

            workHandler.removeCallbacksAndMessages(null);

            workHandler = null;

        }

   if (mHandler != null) {

       mHandler.removeCallbacksAndMessages(null);

       mHandler = null;

   }

 

    }

 

4、使用AsyncTask

使用AsyncTask,AsyncTask是一個封裝好的輕量級異步任務處理類,輕量級,顧名思義,一些重量級的異步任務還是自己搞個實現,大部分場景下,AsyncTask夠用了。

 

相比AsyncTask,我更喜歡使用handler+Thread解決異步任務。

一個異步任務使用AsyncTask很方便,多個異步任務使用handler+thread更好。

 

有一種場景非常適合使用AsyncTask:需要顯示進度值的場景,使用這個封裝好的類,方便理解,節省代碼

輕量級異步處理AsyncTask

/**

  * 步驟1:創建AsyncTask子類

  * 注:

  *   a. 繼承AsyncTask類

  *   b. 為3個泛型參數指定類型;若不使用,可用java.lang.Void類型代替

  *   c. 根據需求,在AsyncTask子類內實現核心方法

  */

 

  private class MyTask extends AsyncTask<Params, Progress, Result> {

 

        ....

 

      // 方法1:onPreExecute()

      // 作用:執行 線程任務前的操作

      // 注:根據需求復寫

      @Override

      protected void onPreExecute() {

           ...

        }

 

      // 方法2:doInBackground()

      // 作用:接收輸入參數、執行任務中的耗時操作、返回 線程任務執行的結果

      // 注:必須復寫,從而自定義線程任務

      @Override

      protected String doInBackground(String... params) {

 

            ...// 自定義的線程任務

 

            // 可調用publishProgress()顯示進度, 之后將執行onProgressUpdate()

             publishProgress(count);

              

         }

 

      // 方法3:onProgressUpdate()

      // 作用:在主線程 顯示線程任務執行的進度

      // 注:根據需求復寫

      @Override

      protected void onProgressUpdate(Integer... progresses) {

            ...

 

        }

 

      // 方法4:onPostExecute()

      // 作用:接收線程任務執行結果、將執行結果顯示到UI組件

      // 注:必須復寫,從而自定義UI操作

      @Override

      protected void onPostExecute(String result) {

 

         ...// UI操作

 

        }

 

      // 方法5:onCancelled()

      // 作用:將異步任務設置為:取消狀態

      @Override

        protected void onCancelled() {

        ...

        }

  }

 

/**

  * 步驟2:創建AsyncTask子類的實例對象(即 任務實例)

  * 注:AsyncTask子類的實例必須在UI線程中創建

  */

  MyTask mTask = new MyTask();

 

/**

  * 步驟3:手動調用execute(Params... params) 從而執行異步線程任務

  * 注:

  *    a. 必須在UI線程中調用

  *    b. 同一個AsyncTask實例對象只能執行1次,若執行第2次將會拋出異常

  *    c. 執行任務中,系統會自動調用AsyncTask的一系列方法:onPreExecute() 、doInBackground()、onProgressUpdate() 、onPostExecute()

  *    d. 不能手動調用上述方法

  */

  mTask.execute();

 

注意:doInBackground()是在工作線程運行的方法,不能調用UI;onPostExecute()是在主UI運行的方法,可以更新UI

 

 

 

總結一下

 

Thread + 消息機制

優點:使用非常靈活(自己手寫的代碼一般也是最多的)一般只在Activity里使用,主線程,工作線程均可實現自己的handler機制

缺點:Activity掛了,也就跟着掛了,需要后台運行那就用IntentService

 

IntentService + ResultReceiver

優點:在后台運行,一般情況下不會被殺死

缺點:官網推薦采用localBroadcast通信,手寫代碼較多。

 

AsyncTask

優點:被封裝過,需要顯示進度條的情況下非常方便,可以串行,也可以並行

缺點:沒那么靈活,只能在主線程里創建

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM