根據源碼註釋說明, handler設計目的如下:
There are two main uses for a Handler: (1) to schedule messages and
runnables to be executed as some point in the future; and (2) to enqueue
an action to be performed on a different thread than your own.
Handler有兩個主要用途:
1. 把 Message 和 Runnable 安排在未來的某個時間點執行;
2. 把某些操作放入其他的線程中執行.
注意, Handler 只是發送消息的一個工具, 並不是使用 Thread 所必須的.
具體機制
-
Handler 初始化: 初始時會獲取當前
Thread
的Looper
, 其中 android 主線程會自動初始化一個Looper
, 而自己創建的線程則需要自己維護Looper
(通過Looper.prepare
創建, 通過Looper.loop
開啓處理message
的循環 ).public Handler(Callback callback, boolean async) { mLooper = Looper.myLooper(); if (mLooper == null) { throw new RuntimeException( "Can't create handler inside thread that has not called Looper.prepare()"); } mQueue = mLooper.mQueue; // 獲取對應線程的Looper的MessageQueue mCallback = callback; mAsynchronous = async; }
-
Handler發送消息:
Handler
發送消息是把Message
發送給Looper
內的MessageQueue
, 所有類型的消息發送到最後都是調用的enqueueMessage
. 而handler.enqueueMessage
則是調用的MessageQueue.enqueueMessage
// Handler.enqueueMessage private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) { msg.target = this; if (mAsynchronous) { msg.setAsynchronous(true); } return queue.enqueueMessage(msg, uptimeMillis); }
// MessageQueue.enqueueMessage 省略了部分代碼 boolean enqueueMessage(Message msg, long when) { synchronized (this) { if (mQuitting) { msg.recycle(); return false; } msg.when = when; Message p = mMessages; boolean needWake; if (p == null || when == 0 || when < p.when) { // 如果當前隊列爲空/已阻塞, 則喚醒 msg.next = p; mMessages = msg; needWake = mBlocked; } else { // 沒有阻塞, 把新消息放入消息隊列中(鏈表) needWake = mBlocked && p.target == null && msg.isAsynchronous(); Message prev; for (;;) { prev = p; p = p.next; if (p == null || when < p.when) { break; } if (needWake && p.isAsynchronous()) { needWake = false; } } msg.next = p; // invariant: p == prev.next prev.next = msg; } if (needWake) { nativeWake(mPtr); } } return true; }
-
處理消息:
Looper
中會死循環查找MessageQueue
, 如果next Message != null
, 那麼這個message
就會交給它內部的target Handler
處理 (msg.target.dispatchMessage(msg)
) ;// 省略了部分代碼, 僅保留邏輯部分 public static void loop() { final Looper me = myLooper(); final MessageQueue queue = me.mQueue; for (;;) { Message msg = queue.next(); // 可能阻塞 if (msg == null) { return; } msg.target.dispatchMessage(msg); msg.recycleUnchecked(); // 清空 } }
/** * 由此可知, 如果message中包含runnable, 或者Handler實例化時傳入了callback, * 那麼handler子類重寫的handleMessage就不會執行了. */ public void dispatchMessage(Message msg) { if (msg.callback != null) { // 調用 Message 內部的 Runnable callback handleCallback(msg); } else { if (mCallback != null) { // 使用構造方法中傳入的Handler內部的Callback接口 if (mCallback.handleMessage(msg)) { return; } } // 或者使用子類的處理方式 handleMessage(msg); } }
新建Thread的兩種方式
第一種:
new Thread(new Runnable() {
@Override
public void run() {
Log.i("TAG", "run on Runnable");
}
}) {
@Override
public void run() {
super.run();
Log.i("TAG", "run on Thread");
}
}.start();
這種創建方式線程在執行完代碼後( 先執行 Thread.run, Runnable 的 run 執行在 Thread.run 的 super 裏面 )就結束了.
第二種:
new Thread(new Runnable() {
@Override
public void run() {
Looper.prepare();
Log.i("TAG", "run on Runnable");
Looper.loop();
}
}).start();
這種方式開啓了死循環, Thread 會一直存活下去. 可以命名此 Thread, 使用 getLooper().quit 來銷燬.
HandlerThread
這個類繼承自Thread,並在內部start時自動創建出Looper循環,所以可以使用new Handler(HandlerThread.getLooper())
的方式很方便的去關聯一個Handler,在循環開啓一個較長時間存活的子線程時可以使用。如果不再需要時,可以通過HandlerThread.quitSafely
去退出該線程。
Handler的bug
在使用Handler去循環發送消息時容易出現丟失消息的問題,例如多次在接收到消息時再次延遲發送一個消息時最容易出現,這種場景下就不要使用Handler的方式去處理了,可以直接在Thread.run中添加sleep處理。