1. 程式人生 > >Android 開發中的訊息機制 Looper基礎

Android 開發中的訊息機制 Looper基礎

Looper物件線上程中的應用及常見 RuntimeException 異常處理

一、前言

           在耗時操作時開啟新執行緒,新執行緒需要開啟一個Looper物件,啟動一個訊息迴圈。主執行緒預設會有一個Looper,而開啟的新執行緒沒有 Looper 需要建立Looper物件,與當前執行緒進行繫結。開啟訊息迴圈,對子執行緒的進行訊息處理操作。

       當在主執行緒中要進行某一操作比較耗時時,就需要開啟新執行緒來處理,主執行緒通常等待時間在 5 秒左右,大於 5 秒的操作會報錯,所以需要子執行緒。

二、子執行緒中未繫結 Looper 物件引起的異常及處理

出現異常的程式碼:(以下程式碼是本人檔案的部分程式碼,部分類是由於需要個人建立的)

new Thread(new Runnable() {
                    @Override
                    public void run() {
                        GetMessageByIdFromWeb getMById = new GetMessageByIdFromWeb(); //獲取物件 ById
                        message = getMById.getMessage(_id);
                        Toast.makeText(context,"該物件的 id:"+message.getId()+","+"content:"+message.getContent(),Toast.LENGTH_SHORT).show();
                    }
                }).start();

      報異常:


處理後的程式碼:

new Thread(new Runnable() {
                    @Override
                    public void run() {
                        Looper.prepare();//修改處
                        GetMessageByIdFromWeb getMById = new GetMessageByIdFromWeb(); //獲取物件 ById
                        message = getMById.getMessage(_id);
                        Toast.makeText(context,"該物件的 id:"+message.getId()+","+"content:"+message.getContent(),Toast.LENGTH_SHORT).show();
                        Looper.loop();//修改處
                    }
                }).start();

      Looper.prepare();//該語句代表開啟一個數據迴圈

      Looper.loop();//該語句之後的程式碼不執行

      正確執行,不報異常

三、Looper 的理解

  (1)handler、message、looper、MessageQueue 物件之間的關聯

簡單理解:子執行緒中訊息處理handler 與 message 與 looper。handler 有一個訊息佇列  MessageQueue , handler 處理的訊息 Message 物件都來自這個訊息佇列 MessageQueue  拿出來的 Message,Looper 負責遍歷和拿取訊息佇列內的訊息給 handler。每一個執行緒對應繫結一個 Looper 物件。

  (2)子執行緒需要新建 Looper物件開啟訊息迴圈

handler 其代理作用,具體物件傳送請求,通過 handler,這裡主執行緒通過 handler.sendMessage(Message msg);來發送訊息之子執行緒。handler 把這個請求存入 messageQueue 佇列;Looper 物件是來處理 該佇列的,例項化 Looper 物件,開啟一個訊息迴圈,的護理子執行緒與主執行緒的互動。Looper 中有一個訊息迴圈,迴圈讀取 MessageQueue 佇列的訊息,當底層有訊息請求時,繼續存返入該佇列,例項化的 Looper 物件迴圈遍歷訊息,交給對應的 Handler 處理;每個執行緒 handler對應一個Looper ,僅繫結一個 looper 物件,開啟訊息迴圈。handler 處理對請求進行處理,呼叫相關方法相應操作,進行介面的修改。

      (3)主執行緒預設有一個 Looper物件

Looper 是用來封裝訊息迴圈和訊息佇列 (MessageQueue) 的一個類,用於在 android 多執行緒、子執行緒中進行訊息處理。主執行緒預設有一個Looper訊息處理物件。handler其實可以看做是一個工具類,用來向訊息佇列中插入訊息的。handler 與當前執行緒進行繫結,Looper類用來為一個執行緒開啟一個訊息迴圈。 Looper物件通過MessageQueue來存放訊息和事件。一個執行緒只能有一個Looper,對應一個MessageQueue。

四、looper 要點

      1. Looper類用來為一個執行緒開啟一個訊息迴圈。 


      2. 通常是通過Handler物件來與Looper進行互動的。Handler用來向指定的Looper傳送訊息及定義處理方法。 
 預設情況下Handler會與其被定義時所線上程的Looper繫結。在主執行緒中通過handler.sendmessage傳送訊息


       3. 在非主執行緒中直接new Handler() 會報如下的錯誤: 
AndroidRuntime Uncaught handler: thread Thread-8 exiting due to uncaught exception 
AndroidRuntime java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare() 


原因是非主執行緒中預設沒有建立Looper物件,需要先呼叫Looper.prepare()啟用Looper。 

      4. Looper.loop(); 讓Looper開始工作,從訊息佇列裡取訊息,處理訊息。 

    注意:寫在Looper.loop()之後的程式碼不會被執行,這個函式內部應該是一個迴圈,當呼叫mHandler.getLooper().quit()後,loop才會中止,其後的程式碼才能得以執行。 

      5. 基於以上知識,可實現主執行緒給子執行緒(非主執行緒)傳送訊息。

五、關係圖