Android應用程序消息處理機制

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

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

主要涉及三個類:post

  • MessageQueue
  • Looper
  • Handler

Android應用程序每啓動一個線程,都爲其建立一個消息隊列,而後進入到一個無限循環之中。而後不斷檢查隊列中是否有新消息須要處理。若是沒有,線程就會進入睡眠狀態,反之會對消息進行分發處理。spa

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

建立消息隊列

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

+------------+     +------+
      |MessageQueue+----^+Looper|
      +-----+------+     +------+
            |                    
            |                    
            |                    
+-----------+------+     +------+
|NativeMessageQueue+^----+Looper|
+------------------+     +------+

        A----^B表示B中保存A的引用

建立過程以下所示:對象

  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上,當其餘線程往管道寫數據時,本線程便會被喚醒以進行消息處理。

消息循環

+------+    +------------+  +------------------+  +--------------+                    
          |Looper|    |MessageQueue|  |NativeMessageQueue|  |Looper(Native)|                    
          +--+---+    +------+-----+  +---------+--------+  +-------+------+                    
             |               |                  |                   |                           
             |               |                  |                   |                           
+-------------------------------------------------------------------------------+               
|[msg loop]  |   next()      |                  |                   |           |               
|            +------------>  |                  |                   |           |               
|            |               |                  |                   |           |               
|            |               |                  |                   |           |               
|            |               | nativePollOnce() |                   |           |               
|            |               |    pollOnce()    |                   |           |               
|            |               +----------------> |                   |           |               
|            |               |                  |                   |           |              
|            |               |                  |                   |           |               
|            |               |                  |                   |           |               
|            |               |                  |                   |           |               
|            |               |                  |     pollOnce()    |           |               
|            |               |                  +-----------------> |           |               
|            |               |                  |                   |           |               
|            |               |                  |                   | epoll_wait()              
|            |               |                  |                   +--------+  |               
|            |               |                  |                   |        |  |               
|            |               |                  |                   |        |  |               
|            |               |                  |                   | <------+  |               
|            |               |                  |                   | awoken()  |               
|            +               +                  +                   +           |               
|                                                                               |               
|                                                                               |               
+-------------------------------------------------------------------------------+
  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機制在以前創建的管道上等待數據寫入。接收到數據後立刻讀取並返回結果。

消息發送

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

消息發送過程主要由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會被調用。事件

相關文章
相關標籤/搜索