android機制系列之三 Handler實現原理
系列之三 執行緒間通訊-Handler
備註:直接跳過了系列2,是因為Binder十分複雜,想要學習後,並總結一些可能比較難。暫時跳過,先分享一些簡單的。不過從目前研究的廣播機制原理,contentProvider都繞不開binder。所以會盡快給自己壓力學習起來!
Handler是android上最常用的執行緒間通訊工具。handler是基於某個thread/loop(主或者次)來給外部呼叫者去操作的。主要的用途是跨執行緒呼叫,操作主執行緒更新;更重要的是讓很多的操作能夠排隊。android原始碼framework中就有利用handler實現的狀態機
,而且應用到了wifi和藍芽上。
接下來講handler的原理。
初始化的時候,會建立一個Looper
和MessageQueue
,如果是自定義的thread,就得手動的開始looper()
。我們看了下HandlerThread
類的原始碼就知道,主要就是Thread封裝了一下looper.perpare()和loop()
。然後loop跑起來以後,就會開啟一個死迴圈。會一直讀取MessageQueue的next()
方法,如果next()
裡面沒訊息了,底層讓它等待著,達到阻塞執行緒的目的(當然需要空閒等待)。然後當生產者
(sendMessage的地方很多,這裡指的就是架構設計上的對於Handler而言外部整體)sendMessage()的時候,實際就是給MessageQueue佇列追加,然後順便wake
消費者
loop執行緒,讓前面的等待繼續下去。 提取出來的訊息,會有
dispatchMessage()
做一些Runnable
或者callback
的判斷,一般的情況會給到我們熟悉的handlerMessage()
裡面。這個就是應用層,我們需要實現的方法。 所以回顧來看,Handler外任意執行緒都往一個對列裡丟資料;然後,就在一個特殊的執行緒裡面(HandleMessage也在這個執行緒裡),對這個佇列操作,或者調整順序(AtFront等方法)。
一般地,由於使用了非靜態的(普通的)內部類或者匿名內部類物件,這種一般出現在Handler和Thread直接new的時候
擴充套件1 底層實現:
這個wait/wake在android上實現是native層是使用epoll + pipe管道實現的。後來android6.0使用了eventfd。如果沒有特別的研究的話,我們不需要關注Handler的底層實現機制,我們需要的是一個等待喚醒的模型。為什麼不直接用一些java層的等待喚醒比如object的,主要是android是一個系統,cpp程式碼中也有Handler機制的。所以google建立了一個從上到下的方案。
擴充套件2 記憶體洩漏:
為何內部類或者匿名new的物件會產生持有外部引用?
內部類是java編譯器,在編譯的時候,預設給的建構函式攜帶了一個外部引用進去。這個內部類我們可以使用外部類的一些方法、變數,而加上static的時候,就提示這些方法和變數錯誤了;這就是內部類持有了外部類引用的證據。擴充套件3 framework狀態機:
./core/java/com/android/internal/util/StateMachine.java