本系列文章將分N篇介紹Android中的消息機制。
Android的應用程序和Windows應用程序一樣,都是由消息驅動的。在Android操作系統中,谷歌也實現了消息循環處理機制。
學習Android的消息機制,有幾個設計概念我們必須瞭解:
ThreadLocalData
,ThreadLocal的作用是提供線程內的局部變量(TLS),這種變量在線程的生命週期內起作用,每一個線程有他自己所屬的值(線程隔離)。
5、6為牽涉到的概念,不是本文重點。會另起文章討論
平時我們最常使用的就是Message與Handler了,如果使用過HandlerThread或者自己實現類似HandlerThread的東西可能還會接觸到Looper,而MessageQueue是Looper內部使用的,對於標準的SDK,我們是無法實例化並使用的(構造函數是包可見性)。
我們平時接觸到的Looper、Message、Handler都是用JAVA實現的,Android是一個基於Linux的系統,底層用C、C++實現的,而且還有NDK的存在,Android消息驅動的模型為了消息的及時性、高效性,在Native層也設計了Java層對應的類如Looper、MessageQueue等。
一句話總結為:Looper不斷從MessageQueue中取出一個Message,然後交給其對應的Handler處理。
他們之間的類圖如下:
從上文兩張圖中我們可以得到以下結論:
還有一點要說明的是:普通的線程是沒有looper的,如果需要looper對象,那麼必須要先調用Looper.prepare()方法,而且一個線程只能有一個looper。調用完以後,此線程就成為了所謂的LooperThread,若在當前LooperThread中創建Handler對象,那麼此Handler會自動關聯到當前線程的looper對象,也就是擁有looper的引用。
下面是官方給出的LooperThread最標準的用法。
class LooperThread extends Thread {
public Handler mHandler;
public void run() {
Looper.prepare();
mHandler = new Handler() {
public void handleMessage(Message msg) {
// process incoming messages here
}
};
Looper.loop();
}
Handler發送消息後添加消息到消息隊列,然後消息在恰當時候出列,都是由Handler來執行,那麼是如何完成跨線程通信的?
這裡就牽涉到了Linux系統的跨線程通信的知識,Android中採用的是Linux中的管道通信。
Looper是通過管道(pipe)實現的。
關於管道,簡單來說,管道就是一個文件。
在管道的兩端,分別是兩個打開文件文件描述符,這兩個打開文件描述符都是對應同一個文件,其中一個是用來讀的,別一個是用來寫的。
一般的使用方式就是,一個線程通過讀文件描述符中來讀管道的內容,當管道沒有內容時,這個線程就會進入等待狀態,而另外一個線程通過寫文件描述符來向管道中寫入內容,寫入內容的時候,如果另一端正有線程正在等待管道中的內容,那麼這個線程就會被喚醒。這個等待和喚醒的操作是如何進行的呢,這就要藉助Linux系統中的epoll機制了。 Linux系統中的epoll機制為處理大批量句柄而作了改進的poll,是Linux下多路複用IO接口select/poll的增強版本,它能顯著減少程序在大量併發連接中只有少量活躍的情況下的系統CPU利用率。
(01) pipe(wakeFds),該函數創建了兩個管道句柄。
(02) mWakeReadPipeFd=wakeFds[0],是讀管道的句柄。
(03) mWakeWritePipeFd=wakeFds1,是寫管道的句柄。
(04) epoll_create(EPOLL_SIZE_HINT)是創建epoll句柄。
(05) epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, & eventItem),它的作用是告訴mEpollFd,它要監控mWakeReadPipeFd文件描述符的EPOLLIN事件,即當管道中有內容可讀時,就喚醒當前正在等待管道中的內容的線程。
這樣一個線程(比如UI線程)消息隊列和Looper就準備就緒了。
消息隊列創建時,會調用JNI函數,初始化NativeMessageQueue對象。NativeMessageQueue則會初始化Looper對象。Looper的作用就是,當Java層的消息隊列中沒有消息時,就使Android應用程序主線程進入等待狀態,而當Java層的消息隊列中來了新的消息後,就喚醒Android應用程序的主線程來處理這個消息。
由於鄙人C++荒廢,在此不做過多探討。
關於C++層邏輯可參考文章:
Android應用程序消息處理機制(Looper、Handler)分析
Android消息機制-Handler(native篇)
Android消息處理機制(Handler、Looper、MessageQueue與Message)
Android消息機制架構和源碼解析
本系列文章參考的資料還有:
書籍:深入理解Android內核設計思想
Android源碼分析-消息隊列和Looper
Android消息循環機制源碼分析
Handler Looper MessageQueue 詳解
</div>