Android的Handler機制原理
建立流程:
主執行緒建立一個looper(只能有一個Looper),建立looper的同時,會在looper的內部建立一個訊息佇列(MessageQueue) 建立Handler的時候,我們會取出當前執行緒的Looper,不斷的去輪詢MessageQueue中的Message。
整體流程:
Handler在子執行緒中傳送的訊息,實際上就是在MessageQueue中新增一條Message,通過Looper中的訊息迴圈取得Message交給Handler處理。
原始碼分析:
ThreadLocal概念:執行緒區域性變數,是一種多執行緒間併發訪問變數的解決方案。與其synchronized等加鎖的方式不同,ThreadLocal完全不提供鎖,而使用以空間換時間的手段,為每個執行緒提供變數的獨立副本,以保障執行緒安全。 從效能上說,ThreadLocal不具有絕對的優勢,在併發不是很高的時候,加鎖的效能會更好,但作為一套與鎖完全無關的執行緒安全解決方案,在高併發量或者競爭激烈的場景,使用ThreadLocal可以在一定程度上減少鎖競爭。
通過ThreadLocal來建立執行緒的內部變數。只建立一個Looper
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
public static void prepare() { prepare(true); } private static void prepare(boolean quitAllowed) { if (sThreadLocal.get() != null) { throw new RuntimeException("Only one Looper may be created per thread"); } sThreadLocal.set(new Looper(quitAllowed)); }
Looper的構造方法,在建立Looper的時候,MessageQueue物件也被建立好了,這樣就能保證Looper中持有一個MessageQueue
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
MessageQueue的資料結構其實並不是佇列,這裡採用了單鏈表的形式,因為單鏈表在插入和刪除時,比佇列有優勢。
Handler建立的時候,會呼叫Looper.myLooper這個方法來得到Looper
mLooper = Looper.myLooper();
Looper.myLooper這個方法其實就是從ThreadLocal中得到Looper
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
Handler處理訊息
/**
* Handle system messages here.
*/
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
預設情況下,Android中新開啟的執行緒,是沒有開啟訊息迴圈的,如果要線上程中使用Handler,那麼就要先呼叫Looper.prepare,主執行緒中,自動建立了Looper物件
Handler是Looper的一個介面,用來想Looper的MessageQueue中傳送Message
在非UI執行緒中,直接new Handler()是不可以的,因為Handler需要傳送訊息到MessageQueue,而你所在的執行緒中沒有MessageQueue,所以必須要先建立Looper物件。