Android應用程序消息處理機制

cg4f 9年前發布 | 9K 次閱讀 Android Android開發 移動開發

Android的消息處理機制主要分為四個部分:

  • 創建消息隊列
  • 消息循環
  • 消息發送
  • 消息處理

主要涉及三個類:

  • MessageQueue
  • Looper
  • Handler

Android應用程序每啟動一個線程,都為其創建一個消息隊列,然后進入到一個無限循環之中。然后不斷檢查隊列中是否有新消息需要處理。如果沒有,線程就會進入睡眠狀態,反之會對消息進行分發處理。

下面根據上面所說的進行詳述。

創建消息隊列

整個創建過程涉及到兩個類:MessageQueue 和 Looper。它們在C++層有兩個對應的類:NativeMessageQueue和Looper。其關系如下圖所示:

          +------+    +------------+  +------------------+  +--------------+                    
          |Looper|    |MessageQueue|  |NativeMessageQueue|  |Looper(Native)|                    
          +--+---+    +------+-----+  +---------+--------+  +-------+------+                    
             |               |                  |                   |                           
             |               |                  |                   |                           
+-------------------------------------------------------------------------------+               
|[msg loop]  |   next()      |                  |                   |           |               
|            +------------>  |                  |                   |           |               
|            |               |                  |                   |           |               
|            |               |                  |                   |           |               
|            |               | nativePollOnce() |                   |           |               
|            |               |    pollOnce()    |                   |           |               
|            |               +----------------> |                   |           |               
|            |               |                  |                   |           |              
|            |               |                  |                   |           |               
|            |               |                  |                   |           |               
|            |               |                  |                   |           |               
|            |               |                  |     pollOnce()    |           |               
|            |               |                  +-----------------> |           |               
|            |               |                  |                   |           |               
|            |               |                  |                   | epoll_wait()              
|            |               |                  |                   +--------+  |               
|            |               |                  |                   |        |  |               
|            |               |                  |                   |        |  |               
|            |               |                  |                   | <------+  |               
|            |               |                  |                   | awoken()  |               
|            +               +                  +                   +           |               
|                                                                               |               
|                                                                               |               
+-------------------------------------------------------------------------------+           

創建過程如下所示:

  1. Looper的prepare或者prepareMainLooper靜態方法被調用,將一個Looper對象保存在ThreadLocal里面。
  2. Looper對象的初始化方法里,首先會新建一個MessageQueue對象。
  3. MessageQueue對象的初始化方法通過JNI初始化C++層的NativeMessageQueue對象。
  4. NativeMessageQueue對象在創建過程中,會初始化一個C++層的Looper對象。
  5. C++層的Looper對象在創建的過程中,會在內部創建一個管道(pipe),并將這個管道的讀寫fd都保存在mWakeReadPipeFd和mWakeWritePipeFd中。
    然后新建一個epoll實例,并將兩個fd注冊進去。
  6. 利用epoll的機制,可以做到當管道沒有消息時,線程睡眠在讀端的fd上,當其他線程往管道寫數據時,本線程便會被喚醒以進行消息處理。

消息循環

         +-------+     +------------+   +------------------+   +--------------+                        
          |Handler|     |MessageQueue|   |NativeMessageQueue|   |Looper(Native)|                        
          +--+----+     +-----+------+   +---------+--------+   +-------+------+                        
             |                |                    |                    |                               
             |                |                    |                    |                               
sendMessage()|                |                    |                    |                               
+----------> |                |                    |                    |                               
             |                |                    |                    |                               
             |enqueueMessage()|                    |                    |                               
             +--------------> |                    |                    |                               
             |                |                    |                    |                               
             |                |                    |                    |                               
             |                |                    |                    |                               
             |                |  nativeWake()      |                    |                               
             |                |    wake()          |                    |                               
             |                +------------------> |                    |                               
             |                |                    |                    |                               
             |                |                    |    wake()          |                               
             |                |                    +------------------> |                               
             |                |                    |                    |                               
             |                |                    |                    |                               
             |                |                    |                    |write(mWakeWritePipeFd, "W", 1)
             |                |                    |                    |                               
             |                |                    |                    |                               
             |                |                    |                    |                               
             |                |                    |                    |                               
             |                |                    |                    |                               
             +                +                    +                    +                          

  1. 首先通過調用Looper的loop方法開始消息監聽。loop方法里會調用MessageQueue的next方法。next方法會堵塞線程直到有消息到來為止。
  2. next方法通過調用nativePollOnce方法來監聽事件。next方法內部邏輯如下所示(簡化):
    a. 進入死循環,以參數timout=0調用nativePollOnce方法。
    b. 如果消息隊列中有消息,nativePollOnce方法會將消息保存在mMessage成員中。nativePollOnce方法返回后立刻檢查mMessage成員是否為空。
    c. 如果mMessage不為空,那么檢查它指定的運行時間。如果比當前時間要前,那么馬上返回這個mMessage,否則設置timeout為兩者之差,進入下一次循環。
    d. 如果mMessage為空,那么設置timeout為-1,即下次循環nativePollOnce永久堵塞。
  3. nativePollOnce方法內部利用epoll機制在之前建立的管道上等待數據寫入。接收到數據后馬上讀取并返回結果。

消息發送

            +------+       +-------+                                                                   
             |Looper|       |Handler|                                                                   
             +--+---+       +---+---+                                                                   
                |               |                                                                       
                |               |                                                                       
    loop()      |               |                                                                       
    [after next()]              |                                                                       
    +---------> |               |                                                                       
                |               |                                                                       
                |dispatchMessage()                                                                      
                +-------------> |                                                                       
                |               |                                                                       
                |               |                                                                       
                |               | handleMessage()                                                       
                |               +-------+                                                               
                |               |       |                                                               
                |               |       |                                                               
                |               | <-----+                                                               
                |               |   (callback or subclass)                                              
                |               |                                                                       
                +               +                       

消息發送過程主要由Handler對象來驅動。

  1. Handler對象在創建時會保存當前線程的looper和MessageQueue,如果傳入Callback的話也會保存起來。
  2. 用戶調用handler對象的sendMessage方法,傳入msg對象。handler通過調用MessageQueue的enqueueMessage方法將消息壓入MessageQueue。
  3. enqueueMessage方法會將傳入的消息對象根據觸發時間(when)插入到message queue中。然后判斷是否要喚醒等待中的隊列。
    a. 如果插在隊列中間。說明該消息不需要馬上處理,不需要由這個消息來喚醒隊列。
    b. 如果插在隊列頭部(或者when=0),則表明要馬上處理這個消息。如果當前隊列正在堵塞,則需要喚醒它進行處理。
  4. 如果需要喚醒隊列,則通過nativeWake方法,往前面提到的管道中寫入一個"W"字符,令nativePollOnce方法返回。

消息處理

+------+       +-------+  |Looper|       |Handler|                                                                   
             +--+---+       +---+---+  |               |                                                                       
                |               |                                                                       
    loop()      |               |                                                                       
    [after next()]              |                                                                       
    +---------> |               |  |               |                                                                       
                |dispatchMessage()                                                                      
                +-------------> |  |               |                                                                       
                |               |                                                                       
                |               | handleMessage()                                                       
                |               +-------+  |               |       |                                                               
                |               |       |                                                               
                |               | <-----+  |               |   (callback or subclass)                                              
                |               |                                                                       
                +               + 

Looper對象的loop方法里面的queue.next方法如果返回了message,那么handler的dispatchMessage會被調用。
a. 如果新建Handler的時候傳入了callback實例,那么callback的handleMessage方法會被調用。
b. 如果是通過post方法向handler傳入runnable對象的,那么runnable對象的run方法會被調用。
c. 其他情況下,handler方法的handleMessage會被調用。

來自:http://segmentfault.com/a/1190000002982318

 本文由用戶 cg4f 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!