1. 程式人生 > >android機制系列之三 Handler實現原理

android機制系列之三 Handler實現原理

系列之三 執行緒間通訊-Handler

備註:直接跳過了系列2,是因為Binder十分複雜,想要學習後,並總結一些可能比較難。暫時跳過,先分享一些簡單的。不過從目前研究的廣播機制原理,contentProvider都繞不開binder。所以會盡快給自己壓力學習起來!


  Handler是android上最常用的執行緒間通訊工具。handler是基於某個thread/loop(主或者次)來給外部呼叫者去操作的。主要的用途是跨執行緒呼叫,操作主執行緒更新;更重要的是讓很多的操作能夠排隊。android原始碼framework中就有利用handler實現的狀態機,而且應用到了wifi和藍芽上。

  接下來講handler的原理。
  初始化的時候,會建立一個LooperMessageQueue,如果是自定義的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的時候
,持有了外部類的引用。而如果在一些延遲操作的時候,生命週期比外部長,容易產生記憶體洩漏。handler一般使用弱引用等來解決記憶體洩漏。事實上最關鍵的,在不需要handler繼續處理的時候,需要將handler的msg和callback都移除。

  • 擴充套件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