解析Android訊息處理機制
——Handler/Thread/Looper & MessageQueue
田海立@CSDN
2011/07/12
Keywords: Android Message HandlerThread Looper UML
本文解析Android如何利用Handler/Thread/Looper以及MessageQueue來實現訊息機制的內部實現。知道了它的內部實現機理之後,以後再遇到使用它們時候的任何問題就駕輕就熟、迎刃而解了。
Android利用執行在HandlerThread線程中的Looper的相應訊息分發/處理,與其他線程中的訊息發送結合,實現完整的訊息處理機制。本文首先介紹這些訊息處理過程中的參與者之間的關係,然後結合WifiService訊息處理的實際執行個體,講解訊息處理的全過程,最後還從線程視圖的角度,重新審視一下線程同步模型。
一、HandlerThread/Looper/MessageQueue的前世今生
是從Froyo從抽取出的HandlerThread、Looper和MessageQueue的關係圖。他們被定義在package android.os。
圖一:HandlerThread/Looper/MessageQueue執行個體關係
HandlerThread是一個Thread,繼承自Thread。它保留著對Looper執行個體的引用,不過這裡還看不到HandlerThread、Looper和MessageQueue如何執行個體化,這要到二、HandlerThread/Looper/MessageQueue執行個體化之後才能看清如何?的。
一看便知,Looper的建構函式是私人的,外界無法直接執行個體化之;要執行個體化,只有通過Looper::prepare()。這樣HandlerThread就與Looper建立了對應關係。對如何建立的是不是已經迫不及待了,那就接著看下一小節。
二、HandlerThread/Looper/MessageQueue執行個體化
上一節只是看了HandlerThread、Looper和MessageQueue之間的靜態視圖關係,他們具體如何執行個體化的,還要看動態執行個體初始化過程。
圖二:HandlerThread/Looper執行個體化
- HandlerThread是一個Thread,在它被執行個體化並執行start()[序列1&2]之後,它的run()方法會在它自己的線程空間執行[序列3]。
- 上節已經提到了Looper的執行個體化是通過Looper::prepare實現的,圖中可以看到Looper::prepare()正是在HandlerThread::run()中被調用而執行個體化[序列4&5]的。
- 而MessageQueue是在Looper的私人建構函式Looper()中執行個體化的。
總結一下,HandlerThread是被顯式地通過new建立的執行個體,而與它綁定在一起的Looper是在HandlerThread的執行過程中被執行個體化的,相應的MessageQueue也是在這個過程中執行個體化的。
三、Looper::loop分發處理訊息
上節重點講了HandlerThread/Looper的執行個體化過程,它發生在Thread::run()這也是線程啟動並執行關鍵,從圖二也看到了Looper::loop()這個訊息處理的核心正是在這裡執行的,下面就看看它到底做了什麼。
圖三:Looper::loop()處理
圖中的所有序列是發生在一個無限迴圈體while (true) {} 中的。
- mQueue:MessageQueue是Looper保留的一份引用,通過它的next()[序列1]擷取MessageQueue中的下一個要處理的訊息,這個過程中如果沒有相應的訊息,執行它的線程會用this.wait()釋放它所擁有的MessageQueue的對象鎖而等待。
- 一旦有訊息到來[序列2],Looper會用獲得的Message的Handler(msg.target)來分發處理訊息[序列3&4]。訊息處理完之後,還要回收[序列5]。
四、Handler實現具體訊息處理
在Looper::loop()訊息處理的順序圖裡看到了Handler,這個訊息分發處理的參與者。下面結合WifiHandler這個具體的Handler看它如何參與到訊息的發送、分發和處理的。
4.1 Handler執行個體化
WifiService中定義了如下的WifiHandler。
圖四、訊息的發送、分發、處理者Handler
看Handler的建構函式是需要Looper的,從上面的分析知道,Looper是在HandlerThread執行中執行個體化的,Looper執行個體如何獲得的呢?看圖一&圖二,知道HandlerThread保留著Looper的應用mLooper,並可通過getLooper()被外面擷取。而Handler的mQueue: MessageQueue可以通過mLooper.mQueue獲得。
所以,Wifi的HandlerThread,WifiHandler可以這樣執行個體化:
HandlerThread wifiThread = new HandlerThread("WifiService");wifiThread.start();mWifiHandler = new WifiHandler(wifiThread.getLooper());
4.2 訊息發送
圖五、訊息發送
通過Message::obtain()可以建立起Message和Target/Handler,what之間的關係,並得到一個Message msg[序列1&2];然後通過msg.sendToTarget()就可以用Handler來具體發送訊息了[序列3&4];通過一系列的調用,最後會通過MessageQueue::enqueueMessage()把訊息放到mMessages上[序列7],還會通過this.notify()通知正在等待新訊息的線程,重新擁有MessageQueue的對象鎖,而處理該訊息。
圖六、MessageQueue與Message的關係
至此,訊息的發送,分發,處理基本上介紹完畢。
4.3 訊息處理
而要具體處理訊息,從圖三的序列4就可知道,整個架構的最後訊息的處理是通過Handler::handleMessager(msg: Message)來完成。所以如果有自己具體要處理的訊息,只要override Handler的handleMessage(msg: Message)方法,並加入自己特定的對訊息的處理即可。
要處理訊息,就看看Message的屬性裡都有什麼。
圖七、Message屬性
重點關注public屬性what是區分具體什麼訊息;可以帶參數arg1, arg2。
五、重新審視5.1 應用指南
上面介紹了訊息處理的全過程,這些對於只是用來發送和處理訊息的應用者來說,可能有些繁雜,這裡梳理一下從應用者角度看,怎麼使用之。
其實四、Handler實現具體訊息處理中的WifiService就是一個典型的應用情境。
實現一個Handler的子類,並Override handleMessage()方法,亦即,實現訊息處理函數handleMessage()。然後分別建立HandlerThread和Hanlder繼承類的執行個體。這樣就可以如4.2裡那樣發訊息了,而訊息處理在handleMessage()中進行。
從應用者角度看,Looper和MessageQueue是訊息處理的內部機制,可以不關注它的實現細節(唯一要知道的,Handler執行個體化的時候,需要通過HandlerThread獲得Looper的執行個體,從而可以傳遞給Handler)。
5.2 線程角度
下面再從線程的角度看一下,訊息處理過程中參與的線程,以及這些線程之間的同步。
顯然的,這裡有線程HandlerThread的參與,而且Looper::loop()就是執行在HandlerThread的run()方法裡,也就是在HandlerThread裡執行,這也就是說訊息的分發處理和執行是在HandlerThread的線程上下文中。另外,還有至少一個線程存在,也就是建立了HandlerThread的線程B,以及執行訊息發送的線程C,B和C有可能是同一線程。
訊息的發送是在另外一個線程裡,就是因為有了多個線程的存在,才有了線程的同步操作。可再次關注一三和圖五中實現線程同步的Java原語wait()/notify()。
結束語
寫本文的初衷並不是為了寫它而寫它,是在研究Android中的Wifi實現時,遇到了實現Wifi的各種具體操作都是通過訊息來實現的,就想探討一下ANDROID訊息處理機制,這樣就邊看邊用ROSE畫了圖,等到訊息的發送/接收/處理的過程都看完了,再回頭看一下整個UML圖,這不就整個一完整的訊息處理機制嘛!
工作這麼多年過來了,回過頭來看看,自己積累了什麼呢,再看一下5、6年前鄙人的BLOG發現那時還是留下了些東西的,而且寫本文時,重溫Java的線程同步機制時,看到當時寫的東西,發現如果是當時是自己理解的東西,並且用自己擅長的領域表達出來,自己回頭再看時,一目瞭然,幾個UML圖就能解決問題了。
參考資料
Google Android source Froyo(2.2) git://android.git.kernel.org/platform/manifest.git
田海立 解析JVM線程同步機制 http://blog.csdn.net/thl789/article/details/566494
修正記錄
2011/07/18 修改標題、摘要及關鍵詞
訊息發送分發處理的主要參與者是Looper, Handler,還有Thread的執行。很多應用情境有他們參與就可完成,HandlerThread倒是WifiService處理時訊息處理的一個特例,所以,在這些關鍵點上去掉HandlerThread。
(本文可自由轉載,但請給出原文連結:http://blog.csdn.net/thl789/article/details/6601558)。
***************************** 全文結束 *******************************