Android消息機制

Handler的作用:
將一個任務切換到 Handler 所在的線程去執行。

Handler,MessageQueue和Looper的關系:
MessageQueue 是消息隊列,內部存儲了一組消息,以隊列的形式對外提供插入和刪除的工作。采用的是單鏈表的數據結構來存儲消息。
Looper 是消息循環,因為 MessageQueue 是消息的存儲單元,并不能處理消息,所以 Looper 來填補這個功能。Looper 會已無限循環的形式去查找是否有新消息,如果有就處理消息,否則一直等待。

ThreadLocal:
ThreadLocal 并不是線程,它的作用是在每個線程中存儲并提供數據,并 Handler 內部可以通過它來獲得當前線程的 Looper。

注意:線程默認是沒有 Looper 的,要使用 Handler 就要先創建 Looper。
UI 線程(AcitivityThread)被創建的時候會初始化 Looper,所以在主線程中默認可以使用 Handler。

延伸:系統為什么不允許在子線程中訪問 UI?
因為 Android 中的 UI 控件不是線程安全的,如果在多線程中并發訪問可能會導致UI控件處于不可預期的狀態。

Handler的工作原理:
Handler 通過 Looper 來構建內部的消息循環系統,通過 Handler 的 post 方法將一個 Runnable 投遞到 Handler 內部的 Looper 中去處理。
也可以通過 send 方法發送一個消息。(post 方法其實最終會調用 send 方法)。
當 send 方法被調用時,它會調用 MessageQueue 的 enqueueMessage 方法將這個消息放入消息隊列中,然后 Looper 發現新消息來后,處理消息,最終消息中的 Runnable 或者 Handler 中的 handleMessage 方法會被調用。

因為 Looper 是運行在創建 Handler 的線程中的,這樣 Handler 的業務邏輯就被切換到創建 Handler 所在的線程去執行了。

ThreadLocal 的工作原理:
ThreadLocal 是一個線程內部的數據存儲類,可以在指定線程中存儲數據。數據存儲后,只有在指定線程中可以獲取到存儲的數據,其他線程則無法獲取。
使用場景:當某些數據是以線程為作用域并且不同線程具有不同的數據副本的時候,或者是復雜邏輯下的對象傳遞(比如監聽器傳遞),可以考慮采用 ThreadLocal。
使用例子:

private ThreadLocal<Boolean> mBooleanThreadLocal = new ThreadLocal<Boolean>();
mBooleanThreadLocal.set(true);
Log.d(TAG,"[Thread#Main]mBooleanThreadLocal = "+mBooleanThreadLocal.get());

new Thread("Thread#1"){
  public void run(){
    mBooleanThreadLocal .set(fasle);
    Log.d(TAG,"[Thread#1]mBooleanThreadLocal = "+mBooleanThreadLocal.get());
  }
}

new Thread("Thread#2"){
  public void run(){
    Log.d(TAG,"[Thread#2]mBooleanThreadLocal = "+mBooleanThreadLocal.get());
  }
}

輸出結果:

[Thread#Main]mBooleanThreadLocal = true
[Thread#1]mBooleanThreadLocal = fasle
[Thread#2]mBooleanThreadLocal = null

可以看出,雖然在不同線程中訪問同一個 ThreadLocal 對象,但是他們通過 ThreadLocal 獲取到的值卻是不一樣。這就是 ThreadLocal 的奇妙之處。

消息隊列的工作原理:
MessageQueue 主要包含兩個操作:插入和讀取。讀取本身會伴隨著刪除操作。

插入對應的方法是 enqueueMessage(往消息隊列中插入一條消息)
讀取對應的方法是 next(從消息隊列中取出一條消息并將其從消息隊列中刪除)

next 是一個無限循環的方法,如果消息隊列中沒有消息,那么 next 方法就會一直阻塞,當有新消息到來時,next 方法會返回這條消息并將其從單鏈表中移除。

Looper的工作原理:
如何創建一個 Loopre :通過 Looper.prepare() 即為當前線程創建一個 Looper,接著通過 Looper.loop() 來開啟消息循環。

new Thread("Thread#1"){
  public void run(){
    Looper.prepare();
    Handler handler = new Handler();
    Looper.loop();
  }
}.statrt();
  1. Looper 提供了 prepareMainLooper 方法為主線程(ActivityThread)創建 Looper(本質也是通過 prepare 方法實現)
  2. Looper 提供了 getMainLooper 方法,可以在任何地方獲取到主線程的 Looper.
  3. Looper 提供了 quit和quitSafely 方法來退出一個 Looper,兩者區別是 quit 是直接退出,quitSafely 只是設定一個退出標記,然后把消息隊列中已有消息處理完畢后才安全退出。

Handler的工作原理:
Handler 發送消息的過程僅僅是向消息隊列中插入一條消息,MessageQueue 的 next 方法就會返回這條消息給 Looper,Looper 接收到消息后就開始處理了,最終消息由 Looper交由 Handler 處理,即 Handler 的 dispatchMessage 方法會被調用,這時 Handler 就進入了消息處理階段。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容