Handler運(yùn)行機(jī)制是Android消息處理機(jī)制的上層接口. 依靠Looper, MessageQueue, Message支撐/協(xié)作.
在主線(xiàn)程中不能放置耗時(shí)任務(wù), 否則會(huì)引起ANR. 所以一般耗時(shí)任務(wù)會(huì)放在子線(xiàn)程當(dāng)中. 由于Android開(kāi)發(fā)規(guī)范, 在子線(xiàn)程中不能進(jìn)行UI操作. 不可避免地涉及進(jìn)行線(xiàn)程之間通信問(wèn)題. 所以有人說(shuō), Handler運(yùn)行機(jī)制就是用來(lái)處理UI線(xiàn)程與子線(xiàn)程之間的通信的. 這僅僅是Handler運(yùn)行機(jī)制的一個(gè)應(yīng)用場(chǎng)景. 比如還可以實(shí)現(xiàn)子線(xiàn)程向子線(xiàn)程發(fā)送消息, 可以參考下這篇文章.
四個(gè)重要角色
Message
Message
是消息的載體, 比較重要的兩個(gè)字段是obj
與 what
字段, obj
就是需要傳遞消息的內(nèi)容, what
標(biāo)志消息的類(lèi)型, 方便在接收的時(shí)候處理.
MessageQueue
存儲(chǔ)Meesage
的單鏈表, 向外提供讀取next
方法, 與enqueueMessage
入隊(duì)操作.
Looper
維護(hù)MessageQueue
, 開(kāi)始工作時(shí), 不斷從MessageQueue
中取出Message
分發(fā)給他們的target
(其實(shí)就是他們對(duì)應(yīng)的handler
). 一個(gè)線(xiàn)程中只能有一個(gè)Looper對(duì)象.
Handler
消息的發(fā)送者與消息的處理者
一個(gè)經(jīng)典的例子
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();
}
}
這里通過(guò)繼承Thread
,創(chuàng)建了一個(gè)LooperThread
的線(xiàn)程類(lèi), run
方法中先調(diào)用了Looper.prepare()
, 然后創(chuàng)建了一個(gè)Handler對(duì)象, 最后調(diào)用了Looper.loop()
方法.
接下來(lái), 我們通過(guò)源碼分析看看究竟發(fā)生了什么.
Looper.Prepare
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
方法可以重載, 先會(huì)判斷sThreadLocal.get()
是否為空, 為空的話(huà), 先new Looper(quitAllowed)
創(chuàng)建了一個(gè)Looper對(duì)象, 然后把這個(gè)Looper對(duì)象保存在了sThreadLocal
中. 可以想象當(dāng)我們?cè)俅卧诋?dāng)前線(xiàn)程調(diào)用Looper.prepare
方法時(shí), 這時(shí)的sThreadLocal.get()
就不為空了, 會(huì)向我們拋出一個(gè)Only one Looper may be created per thread
異常. 由此可以保證我們每個(gè)線(xiàn)程最多擁有一個(gè)Looper對(duì)象.
剛才構(gòu)造Looper對(duì)象的過(guò)程中, 究竟又做了什么呢?
我們看看Looper的構(gòu)造方法
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
可以看到內(nèi)容只有兩行. 分別為L(zhǎng)ooper的兩個(gè)成員變量賦值, 創(chuàng)建了一個(gè)MessageQueue, Looper綁定了當(dāng)前線(xiàn)程.
總結(jié)下就是: Looper.prepare
方法在當(dāng)前線(xiàn)程中創(chuàng)建了一個(gè)Looper
對(duì)象, Looper
對(duì)象的創(chuàng)建又導(dǎo)致了MessageQueue
對(duì)象創(chuàng)建. 并且綁定當(dāng)前線(xiàn)程. (Looper和MessageQueue在一個(gè)線(xiàn)程中最多有一個(gè))
創(chuàng)建Handler對(duì)象
Handler對(duì)象的創(chuàng)建我們直接來(lái)看Handler的構(gòu)造方法.
/**
* 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的構(gòu)造方法有好幾個(gè), 其實(shí)做的工作, 不外乎為他的各個(gè)成員變量賦值mLooper
,mQueue
,mCallback
,mAsynchronous
. 分析最復(fù)雜的Handler(Callback callback, boolean async)
方法. Looper.myLooper()
方發(fā)獲得了一個(gè)Looper對(duì)象, 這個(gè)Looper對(duì)象是哪里來(lái)的呢?
/**
* 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()
, 原來(lái)就是從我們?cè)?code>Looper.prepare()中存起來(lái)的Looper, 如果為空, 說(shuō)明我們的prepare
方法根本沒(méi)有執(zhí)行. 拋出Can't create handler inside thread that has not called Looper.prepare()
異常. 接下來(lái)Handler的構(gòu)造方法還做了一件事, 把Looper中維護(hù)的MessageQueue取出來(lái)賦值給了mQueue
字段.
總結(jié)下: 獲取當(dāng)前線(xiàn)程的Looper對(duì)象取出來(lái), 并把他和他維護(hù)的MessageQueue賦值給了Handler的成員變量.
這里有個(gè)問(wèn)題: void handleMessage(Message msg)
又是怎樣被調(diào)用的呢?別急, 讓我們看看Looper.loop()
方法.
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的構(gòu)造方法一樣, 先獲得當(dāng)前線(xiàn)程得Looper對(duì)象. 如果為空, 那一定又是沒(méi)有prepare. 接下來(lái)可以看到for (;;) {}
這樣一個(gè)結(jié)構(gòu), 一個(gè)死循環(huán), 不斷獲取next
Message, 直到Message為空.
這里有個(gè)問(wèn)題: 一直在說(shuō)從隊(duì)列中不斷取Message, Message是多久放入隊(duì)列的?
Message的入隊(duì)時(shí)通過(guò)Handler
對(duì)象的sendxxx
類(lèi)與postxxx
類(lèi)方法實(shí)現(xiàn)的.
- sendxxx類(lèi)
//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);
}
//最后都調(diào)用到這里
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);
}
可以看到最后都執(zhí)行了boolean sendMessageAtTime(Message msg, long uptimeMillis)
方法. 可以看到這里最終調(diào)用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);
}
這就時(shí)我們想要的入隊(duì)操作. 值得留意的是這里的msg.target = this
, 入隊(duì)的Message標(biāo)記了發(fā)送他的Handler.
- postxxx方法
postxxx
方法都用兩個(gè)相同的特征: 都傳入Runnable
對(duì)象, 都最終調(diào)用了一個(gè)sendxxx
方法. 所以說(shuō)postxxx
方法最終還是會(huì)調(diào)用enqueueMessage(queue, msg, uptimeMillis)
讓消息入隊(duì). 好像有一點(diǎn)不對(duì)? 明明傳入的一個(gè)Runnable
對(duì)象, 但是入隊(duì)的時(shí)候, 存入其中卻變成了Message?我們來(lái)看看其中一個(gè)postxxx
方法.
public final boolean postDelayed(Runnable r, long delayMillis)
{
return sendMessageDelayed(getPostMessage(r), delayMillis);
}
可以看到這里多調(diào)用了一個(gè)getPostMessage(r)
方法. 這個(gè)方法就是將我們的Runnable
對(duì)象封裝為Message對(duì)象的關(guān)鍵.
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}
可以看到這里獲得一個(gè)Message后, 將Message的callback字段設(shè)置為了Ruannable對(duì)象. 這下就豁然開(kāi)朗了.
接下來(lái)接著看在MessageQueue中擁有Handler發(fā)送來(lái)的消息后, 會(huì)如何進(jìn)行操作. 在死循環(huán)中. msg.target.dispatchMessage(msg)
讓msg的target(也就是發(fā)送他的Handler)去分發(fā)事件.
/**
* 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
就是再這里最后調(diào)用的. 除此之外, 消息的分發(fā)還有兩條路徑msg.callback
和mCallback.handleMessage(msg)
. msg.callback
還記得嗎?就是postxxx
類(lèi)消息發(fā)送的Runnable
對(duì)象. mCallback.handleMessage(msg)
中的mCallback則是在Handler重載的構(gòu)造方法的參數(shù). 這里一旦設(shè)置了回調(diào),并且其handlerMessage返回值為true, 就可以實(shí)現(xiàn)對(duì)Hadnler的handlerMessage
的攔截.
ps: 有什么疏漏或者錯(cuò)誤的地方還請(qǐng)各位指出.
參考:
- 從Handler.post(Runnable r)再一次梳理Android的消息機(jī)制(以及handler的內(nèi)存泄露)
- 深入理解之 Android Handler
- <<Android開(kāi)發(fā)藝術(shù)探索>>