Android複習之旅--子執行緒更新UI

飄渺雲軒發表於2017-01-10

Android4.0版本後耗時的操作(比如請求網路,下載檔案等)不能在UI主執行緒執行,而且子執行緒也不能直接更新UI介面。而現實的場景確是子執行緒在下載檔案的同時UI介面能顯示相應的進度資訊,既然有了需求,那肯定就會有解決方案。

Android提供了Handler訊息機制和AsyncTask抽象類等去實現子執行緒和UI主執行緒之間的通訊。當然還可以使用Volly,okhttp,Retrofit2.0等第三方開源庫來實現,第三方開源庫使用簡單,功能強大。

but ...,這裡只對Handler和AsyncTask進行總結,至於為什麼, 我是不會告訴你們是因為我懶的[歐耶]

好了,進入正題 ...


Handler 訊息機制

通過Handler訊息機制來實現執行緒間的通訊。

那麼Handler是什麼呢?

Handler 機制主要包括4個關鍵物件,分別是Message、Handler、MessageQueue、Looper。

  • Message 是線上程之間傳遞的訊息,它可以在內部攜帶少量的資訊,用於在不同的執行緒之間交換資料
    Message msg = new Message();
    msg.what = 1;  // 用於攜帶整型資料,區別當前訊息
    msg.obj = object;  //用於攜帶一個Object物件
    //傳送訊息給Handler
    handler.sendMessage(msg);複製程式碼
  • Handler 就是處理者的意思,它主要用於傳送訊息和處理訊息
    Handler handler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            int what = msg.what;
            Object object = msg.obj;
        }        
    };複製程式碼
  • MessageQueue 是訊息佇列的意思,它主要用來存放通過Handler傳送的訊息。通過Handler傳送的訊息會存在MessageQueue中等待處理,每個執行緒中有且僅有一個MessageQueue物件。

  • Looper 是每個執行緒中的MessageQueue的管家,它主要進行訊息迴圈,一旦發現MessageQueue中存在訊息,就會把它取出並傳遞到Handler的handlerMessage()方法中(如果MessageQueue中不存在訊息,Looper會自動阻塞,相當於wait(); 而如果Handler傳送了一個訊息,Looper就會被喚醒),每個執行緒有且僅有一個Looper。

    引用 Carson_Ho Handler在建立的時候可以顯示指定Looper,這樣在Handler在呼叫sendMessage()投遞訊息的時候會將訊息新增到指定的Looper裡面的MessageQueue。如果不指定Looper,Handler預設繫結的是建立它的執行緒的Looper。一般預設即可。


AsyncTask 抽象類

為了可以在子執行緒中更好地對UI進行操作,Android提供了一個很好用地工具類--AsyncTask。使用AsyncTask可以非常簡單地從子執行緒切換到主執行緒,它的原理是基於非同步訊息處理機制的。

class DownLoadTask extends AsyncTask<Void, Integer, Boolean> {
    // 1. 預載入,執行在主執行緒
    @Override
    protected void onPreExecute() {
        super.onPreExecute();
    }
    // 2. 正在載入,執行在子執行緒(主要方法)
    @Override
    protected Boolean doInBackground(Void... params) {
        return false;
    }
    // 3. 更新進度的方法,執行在主執行緒
    @Override
    protected void onProgressUpdate(Integer... values) {
        super.onProgressUpdate(values);
    }
    // 4. 載入結束,執行在主執行緒(主要方法)
    @Override
    protected void onPostExecute(Boolean result){
        super.onPostExecute(result);
    }
}複製程式碼

其中,
第一個泛型引數(對應doInBackground裡的引數型別 ):在執行AsyncTask時需要傳入的引數,用於後臺任務中使用;
第二個泛型引數(對應onProgressUpdate裡的引數型別):在後臺任務執行時,如果需要在介面上顯示當前的進度,則使用該引數作為進度單位;
第三個泛型引數(對應onPostExecute裡的引數型別和doInBackground的返回型別):當任務執行完畢後,如果需要對結果進行返回,則使用該引數作為返回值型別。


希望對你們有所幫助

相關文章