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() | | + + + + | | | | | +-------------------------------------------------------------------------------+
創建過程如下所示:
- Looper的prepare或者prepareMainLooper靜態方法被調用,將一個Looper對象保存在ThreadLocal里面。
- Looper對象的初始化方法里,首先會新建一個MessageQueue對象。
- MessageQueue對象的初始化方法通過JNI初始化C++層的NativeMessageQueue對象。
- NativeMessageQueue對象在創建過程中,會初始化一個C++層的Looper對象。
- C++層的Looper對象在創建的過程中,會在內部創建一個管道(pipe),并將這個管道的讀寫fd都保存在mWakeReadPipeFd和mWakeWritePipeFd中。
然后新建一個epoll實例,并將兩個fd注冊進去。 - 利用epoll的機制,可以做到當管道沒有消息時,線程睡眠在讀端的fd上,當其他線程往管道寫數據時,本線程便會被喚醒以進行消息處理。
消息循環
+-------+ +------------+ +------------------+ +--------------+ |Handler| |MessageQueue| |NativeMessageQueue| |Looper(Native)| +--+----+ +-----+------+ +---------+--------+ +-------+------+ | | | | | | | | sendMessage()| | | | +----------> | | | | | | | | |enqueueMessage()| | | +--------------> | | | | | | | | | | | | | | | | | nativeWake() | | | | wake() | | | +------------------> | | | | | | | | | wake() | | | +------------------> | | | | | | | | | | | | |write(mWakeWritePipeFd, "W", 1) | | | | | | | | | | | | | | | | | | | | + + + +
- 首先通過調用Looper的loop方法開始消息監聽。loop方法里會調用MessageQueue的next方法。next方法會堵塞線程直到有消息到來為止。
- next方法通過調用nativePollOnce方法來監聽事件。next方法內部邏輯如下所示(簡化):
a. 進入死循環,以參數timout=0調用nativePollOnce方法。
b. 如果消息隊列中有消息,nativePollOnce方法會將消息保存在mMessage成員中。nativePollOnce方法返回后立刻檢查mMessage成員是否為空。
c. 如果mMessage不為空,那么檢查它指定的運行時間。如果比當前時間要前,那么馬上返回這個mMessage,否則設置timeout為兩者之差,進入下一次循環。
d. 如果mMessage為空,那么設置timeout為-1,即下次循環nativePollOnce永久堵塞。 - nativePollOnce方法內部利用epoll機制在之前建立的管道上等待數據寫入。接收到數據后馬上讀取并返回結果。
消息發送
+------+ +-------+ |Looper| |Handler| +--+---+ +---+---+ | | | | loop() | | [after next()] | +---------> | | | | |dispatchMessage() +-------------> | | | | | | | handleMessage() | +-------+ | | | | | | | | <-----+ | | (callback or subclass) | | + +
消息發送過程主要由Handler對象來驅動。
- Handler對象在創建時會保存當前線程的looper和MessageQueue,如果傳入Callback的話也會保存起來。
- 用戶調用handler對象的sendMessage方法,傳入msg對象。handler通過調用MessageQueue的enqueueMessage方法將消息壓入MessageQueue。
- enqueueMessage方法會將傳入的消息對象根據觸發時間(when)插入到message queue中。然后判斷是否要喚醒等待中的隊列。
a. 如果插在隊列中間。說明該消息不需要馬上處理,不需要由這個消息來喚醒隊列。
b. 如果插在隊列頭部(或者when=0),則表明要馬上處理這個消息。如果當前隊列正在堵塞,則需要喚醒它進行處理。 - 如果需要喚醒隊列,則通過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 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!