android 原始碼分析(四Handler機制詳解)
Handler機制詳解
Handler執行機制梳理
我們在使用Handler的時候,往往是這樣一個使用步驟:
-
初始化一個Handler物件,重寫其handleMessage方法
-
獲取一個Message物件,並相應的為其what、obj屬性賦值
-
呼叫Handler.sendMessage(msg)方法傳送訊息
-
傳送出來的訊息,將在Handler的handleMessage方法中進行處理
因此,我們從sendMessage方法看Handler執行了什麼邏輯:
frameworks\base\core\java\android\os\Handler.java
public final boolean sendMessage(Message msg) { return sendMessageDelayed(msg, 0); } …… public final boolean sendMessageDelayed(Message msg, long delayMillis) { if (delayMillis < 0) { delayMillis = 0; } return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis); } …… public boolean sendMessageAtTime(Message msg, long uptimeMillis) { boolean sent = false; MessageQueue queue = mQueue; if (queue != null) { msg.target = this; sent = queue.enqueueMessage(msg, uptimeMillis); } else { RuntimeException e = new RuntimeException( this + " sendMessageAtTime() called with no mQueue"); Log.w("Looper", e.getMessage(), e); } return sent; }
由程式碼可知,sendMessage和sendMessageDelayed實際上都是呼叫了sendMessageAtTime方法。
若是採用sendMessage方法傳送的訊息,則uptimeMillis的值=當前時間;
若採用sendMessageAtTime方法傳送訊息,則uptimeMillis的值=當前時間 + delayMillis。
注意“msg.target = this;”這行程式碼,this在這裡指的自然是傳送這個Message的Handler物件,這行程式碼非常重要
最終,我們是通過“queue.enqueueMessage(msg, uptimeMillis);”這行程式碼將Message塞入了一個MessageQueue物件中,我們看看這個方法又做了什麼:
frameworks\base\core\java\android\os\MessageQueue.java
final boolean enqueueMessage(Message msg, long when) { …… synchronized (this) { …… msg.when = when; //Log.d("MessageQueue", "Enqueing: " + msg); Message p = mMessages; if (p == null || when == 0 || when < p.when) { msg.next = p; mMessages = msg; needWake = mBlocked; // new head, might need to wake up } else { Message prev = null; while (p != null && p.when <= when) { prev = p; p = p.next; } msg.next = prev.next; prev.next = msg; needWake = false; // still waiting on head, no need to wake up } } …… return true; }
以上程式碼只做了一件事,將我們的Message加入到MessageQueue中,並根據when這個時間值對我們的MessageQueue中的Message進行了排序。
這個when值,就是之前我們傳進來的那個uptimeMillis。
那麼,訊息被放到了我們的MessageQueue中,又由誰來取出並分發呢?
答案是我們的Looper。
我們的應用程式啟動,主執行緒開啟時,系統會建立一個Looper,並呼叫其loop方法,使其開始輪詢MessageQueue中的訊息:
frameworks\base\core\java\android\app\ ActivityThread.java
public static final void main(String[] args) { …… Looper.prepareMainLooper(); …… Looper.loop(); …… }
frameworks\base\core\java\android\os\Looper.java
public static final void prepareMainLooper() { prepare(); setMainLooper(myLooper()); …… } …… public static final void prepare() { if (sThreadLocal.get() != null) { throw new RuntimeException("Only one Looper may be created per thread"); } sThreadLocal.set(new Looper()); } …… public static final Looper myLooper() { return (Looper)sThreadLocal.get(); } …… public static final void loop() { Looper me = myLooper(); MessageQueue queue = me.mQueue; while (true) { Message msg = queue.next(); // might block if (msg != null) { if (msg.target == null) { return; } …… msg.target.dispatchMessage(msg); …… } } }
Loop方法實際上是維持著一個死迴圈,他不停的從MessageQueue中取到Message並將Message分發。
當MessageQueue中沒有訊息時,Loop會處於阻塞狀態:
Message msg = queue.next(); // might block
Message被分發的程式碼為:
msg.target.dispatchMessage(msg);
這裡的msg.target,即傳送我們這個Message的Handler物件,因此,這行程式碼還是呼叫回了我們的Handler的dispatchMessage方法:
frameworks\base\core\java\android\os\Handler.java
public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } }
程式碼可知,我們通過Handler傳送的訊息,最終由我們Handler的handleMessage方法來進行處理,Handler的這一套執行機制到此完畢。
Handler機制靠什麼保證訊息不混亂
假如現在我們new了幾個Handler,同時去sendMessage,我們如何保證哪個Handler傳送的訊息,就交由哪個Handler的handleMessage方法去處理?
牢記我們傳送訊息和分發訊息的時候的這2行程式碼:
frameworks\base\core\java\android\os\Handler.java
public boolean sendMessageAtTime(Message msg, long uptimeMillis){ boolean sent = false; MessageQueue queue = mQueue; if (queue != null) { msg.target = this; sent = queue.enqueueMessage(msg, uptimeMillis); } …… return sent; }
frameworks\base\core\java\android\os\Looper.java
public static final void loop() { Looper me = myLooper(); MessageQueue queue = me.mQueue; while (true) { Message msg = queue.next(); // might block if (msg != null) { if (msg.target == null) { return; } …… msg.target.dispatchMessage(msg); …… } } }
通過這個“msg.target”,我們就可以保證:哪個Handler傳送的訊息,哪個Handler來處理。
ThreadLocal
ThreadLocal就是執行緒區域性變數,經常使用此方法儲存執行緒內的共享變數。
同一個執行緒內的多個不同的類,可以通過ThreadLocal來共享全域性變數。
當執行緒結束後,對應該執行緒的區域性變數將自動被垃圾回收,所以顯式呼叫該方法清除執行緒的區域性變數並不是必須的操作。
所有在主執行緒new出來的Handler,最後都是通過ThreadLocal取用主執行緒建立的那個Looper,來實現的訊息分發。
Handler機制中,我們通過ThreadLocal來保證一個執行緒中只有一個Looper。
Looper會阻塞主執行緒麼
Looper是不會阻塞主執行緒的,正因為有Looper這個死迴圈,我們的app才能去即時的相應使用者的操作。
不止是我們自己通過程式碼邏輯傳送的Message,包括我們應用中所有的操作,比如開啟一個Activity,呼叫Activity生命週期的方法:onCreate\onResume等,都是通過Handler傳送訊息,由Looper輪訓到來處理的。
因此,Looper不會有阻塞我們的主執行緒。