Handler運行機制是Android消息處理機制的上層接口. 依靠Looper, MessageQueue, Message支撐/協做.html
在主線程中不能放置耗時任務, 不然會引發ANR. 因此通常耗時任務會放在子線程當中. 因爲Android開發規範, 在子線程中不能進行UI操做. 不可避免地涉及進行線程之間通訊問題. 因此有人說, Handler運行機制就是用來處理UI線程與子線程之間的通訊的. 這僅僅是Handler運行機制的一個應用場景. 好比還能夠實現子線程向子線程發送消息, 能夠參考下這篇文章.java
Message
是消息的載體, 比較重要的兩個字段是obj
與 what
字段, obj
就是須要傳遞消息的內容, what
標誌消息的類型, 方便在接收的時候處理.bash
存儲Meesage
的單鏈表, 向外提供讀取next
方法, 與enqueueMessage
入隊操做.less
維護MessageQueue
, 開始工做時, 不斷從MessageQueue
中取出Message
分發給他們的target
(其實就是他們對應的handler
). 一個線程中只能有一個Looper對象.async
消息的發送者與消息的處理者ide
class LooperThread extends Thread {
public Handler mHandler;
public void run() {
Looper.prepare();
mHandler = new Handler() {
public void handleMessage(Message msg) {
// process incoming messages here
}
};
Looper.loop();
}
}
複製代碼
這裏經過繼承Thread
,建立了一個LooperThread
的線程類, run
方法中先調用了Looper.prepare()
, 而後建立了一個Handler對象, 最後調用了Looper.loop()
方法.oop
接下來, 咱們經過源碼分析看看究竟發生了什麼.源碼分析
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));
}
複製代碼
能夠看到prepare
方法能夠重載, 先會判斷sThreadLocal.get()
是否爲空, 爲空的話, 先new Looper(quitAllowed)
建立了一個Looper對象, 而後把這個Looper對象保存在了sThreadLocal
中. 能夠想象當咱們再次在當前線程調用Looper.prepare
方法時, 這時的sThreadLocal.get()
就不爲空了, 會向咱們拋出一個Only one Looper may be created per thread
異常. 由此能夠保證咱們每一個線程最多擁有一個Looper對象.post
剛纔構造Looper對象的過程當中, 究竟又作了什麼呢? 咱們看看Looper的構造方法ui
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
複製代碼
能夠看到內容只有兩行. 分別爲Looper的兩個成員變量賦值, 建立了一個MessageQueue, Looper綁定了當前線程.
總結下就是: Looper.prepare
方法在當前線程中建立了一個Looper
對象, Looper
對象的建立又致使了MessageQueue
對象建立. 而且綁定當前線程. (Looper和MessageQueue在一個線程中最多有一個)
Handler對象的建立咱們直接來看Handler的構造方法.
/** * Default constructor associates this handler with the {@link Looper} for the * current thread. * * If this thread does not have a looper, this handler won't be able to receive messages * so an exception is thrown. */
public Handler() {
this(null, false);
}
/** * Constructor associates this handler with the {@link Looper} for the * current thread and takes a callback interface in which you can handle * messages. * * If this thread does not have a looper, this handler won't be able to receive messages * so an exception is thrown. * * @param callback The callback interface in which to handle messages, or null. */
public Handler(Callback callback) {
this(callback, false);
}
/** * Use the provided {@link Looper} instead of the default one. * * @param looper The looper, must not be null. */
public Handler(Looper looper) {
this(looper, null, false);
}
/** * Use the provided {@link Looper} instead of the default one and take a callback * interface in which to handle messages. * * @param looper The looper, must not be null. * @param callback The callback interface in which to handle messages, or null. */
public Handler(Looper looper, Callback callback) {
this(looper, callback, false);
}
/** * Use the {@link Looper} for the current thread * and set whether the handler should be asynchronous. * * Handlers are synchronous by default unless this constructor is used to make * one that is strictly asynchronous. * * Asynchronous messages represent interrupts or events that do not require global ordering * with respect to synchronous messages. Asynchronous messages are not subject to * the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}. * * @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for * each {@link Message} that is sent to it or {@link Runnable} that is posted to it. * * @hide */
public Handler(boolean async) {
this(null, async);
}
/** * Use the {@link Looper} for the current thread with the specified callback interface * and set whether the handler should be asynchronous. * * Handlers are synchronous by default unless this constructor is used to make * one that is strictly asynchronous. * * Asynchronous messages represent interrupts or events that do not require global ordering * with respect to synchronous messages. Asynchronous messages are not subject to * the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}. * * @param callback The callback interface in which to handle messages, or null. * @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for * each {@link Message} that is sent to it or {@link Runnable} that is posted to it. * * @hide */
public Handler(Callback callback, boolean async) {
if (FIND_POTENTIAL_LEAKS) {
final Class<? extends Handler> klass = getClass();
if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
(klass.getModifiers() & Modifier.STATIC) == 0) {
Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
klass.getCanonicalName());
}
}
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
/** * Use the provided {@link Looper} instead of the default one and take a callback * interface in which to handle messages. Also set whether the handler * should be asynchronous. * * Handlers are synchronous by default unless this constructor is used to make * one that is strictly asynchronous. * * Asynchronous messages represent interrupts or events that do not require global ordering * with respect to synchronous messages. Asynchronous messages are not subject to * the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}. * * @param looper The looper, must not be null. * @param callback The callback interface in which to handle messages, or null. * @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for * each {@link Message} that is sent to it or {@link Runnable} that is posted to it. * * @hide */
public Handler(Looper looper, Callback callback, boolean async) {
mLooper = looper;
mQueue = looper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
複製代碼
能夠看到Handler的構造方法有好幾個, 其實作的工做, 不外乎爲他的各個成員變量賦值mLooper
,mQueue
,mCallback
,mAsynchronous
. 分析最複雜的Handler(Callback callback, boolean async)
方法. Looper.myLooper()
方發得到了一個Looper對象, 這個Looper對象是哪裏來的呢?
/** * Return the Looper object associated with the current thread. Returns * null if the calling thread is not associated with a Looper. */
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
複製代碼
查看源碼看到sThreadLocal.get()
, 原來就是從咱們在Looper.prepare()
中存起來的Looper, 若是爲空, 說明咱們的prepare
方法根本沒有執行. 拋出Can't create handler inside thread that has not called Looper.prepare()
異常. 接下來Handler的構造方法還作了一件事, 把Looper中維護的MessageQueue取出來賦值給了mQueue
字段.
總結下: 獲取當前線程的Looper對象取出來, 並把他和他維護的MessageQueue賦值給了Handler的成員變量.
這裏有個問題: void handleMessage(Message msg)
又是怎樣被調用的呢?別急, 讓咱們看看Looper.loop()
方法.
/** * Run the message queue in this thread. Be sure to call * {@link #quit()} to end the loop. */
public static void loop() {
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue;
// Make sure the identity of this thread is that of the local process,
// and keep track of what that identity token actually is.
Binder.clearCallingIdentity();
final long ident = Binder.clearCallingIdentity();
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
// This must be in a local variable, in case a UI event sets the logger
final Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
}
final long traceTag = me.mTraceTag;
if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
}
try {
msg.target.dispatchMessage(msg);
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
if (logging != null) {
logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
}
// Make sure that during the course of dispatching the
// identity of the thread wasn't corrupted.
final long newIdent = Binder.clearCallingIdentity();
if (ident != newIdent) {
Log.wtf(TAG, "Thread identity changed from 0x"
+ Long.toHexString(ident) + " to 0x"
+ Long.toHexString(newIdent) + " while dispatching to "
+ msg.target.getClass().getName() + " "
+ msg.callback + " what=" + msg.what);
}
msg.recycleUnchecked();
}
}
複製代碼
能夠看到在像Handler的構造方法同樣, 先得到當前線程得Looper對象. 若是爲空, 那必定又是沒有prepare. 接下來能夠看到for (;;) {}
這樣一個結構, 一個死循環, 不斷獲取next
Message, 直到Message爲空.
這裏有個問題: 一直在說從隊列中不斷取Message, Message是多久放入隊列的?
Message的入隊時經過Handler
對象的sendxxx
類與postxxx
類方法實現的.
//sendEmptyMessageDelayed ==> sendMessageDelayed
public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
Message msg = Message.obtain();
msg.what = what;
return sendMessageDelayed(msg, delayMillis);
}
//sendMessageDelayed==> sendMessageAtTime
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) {
MessageQueue queue = mQueue;
if (queue == null) {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
return false;
}
return enqueueMessage(queue, msg, uptimeMillis);
}
複製代碼
能夠看到最後都執行了boolean sendMessageAtTime(Message msg, long uptimeMillis)
方法. 能夠看到這裏最終調用enqueueMessage(queue, msg, uptimeMillis)
.
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
複製代碼
這就時咱們想要的入隊操做. 值得留意的是這裏的msg.target = this
, 入隊的Message標記了發送他的Handler.
postxxx
方法都用兩個相同的特徵: 都傳入Runnable
對象, 都最終調用了一個sendxxx
方法. 因此說postxxx
方法最終仍是會調用enqueueMessage(queue, msg, uptimeMillis)
讓消息入隊. 好像有一點不對? 明明傳入的一個Runnable
對象, 可是入隊的時候, 存入其中卻變成了Message?咱們來看看其中一個postxxx
方法.public final boolean postDelayed(Runnable r, long delayMillis) {
return sendMessageDelayed(getPostMessage(r), delayMillis);
}
複製代碼
能夠看到這裏多調用了一個getPostMessage(r)
方法. 這個方法就是將咱們的Runnable
對象封裝爲Message對象的關鍵.
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}
複製代碼
能夠看到這裏得到一個Message後, 將Message的callback字段設置爲了Ruannable對象. 這下就豁然開朗了.
接下來接着看在MessageQueue中擁有Handler發送來的消息後, 會如何進行操做. 在死循環中. msg.target.dispatchMessage(msg)
讓msg的target(也就是發送他的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);
}
}
複製代碼
這裏的邏輯就很是清晰了, 剛纔想弄清楚的Handler的handleMessage
就是再這裏最後調用的. 除此以外, 消息的分發還有兩條路徑msg.callback
和mCallback.handleMessage(msg)
. msg.callback
還記得嗎?就是postxxx
類消息發送的Runnable
對象. mCallback.handleMessage(msg)
中的mCallback則是在Handler重載的構造方法的參數. 這裏一旦設置了回調,而且其handlerMessage返回值爲true, 就能夠實現對Hadnler的handlerMessage
的攔截.
ps: 有什麼疏漏或者錯誤的地方還請各位指出.