說起Handler機制大家都不陌生,我也看過不少網(wǎng)上相關(guān)文章,都分析的很好,這里作為筆記,通過Handler,Looper,Message,MessageQueue這幾個類,從源碼中來解讀從handler發(fā)送消息到接收到消息的過程。
通常,項目中都會用到Handler來發(fā)送一個異步消息,例如
Message msg = Message.obtain();
// msg.what = 0;
// msg.obj = obj;
// msg.arg1 = 1;
// ...
mHandler.sendMessage(msg);
又或者發(fā)送一個延時消息,例如
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
// TODO ...
Toast.makeText(MainActivity.this, "" , Toast.LENGTH_SHORT).show();
}
}, 1000);
一 、首先,我們來看看發(fā)送一個Message
進(jìn)入sendMessage(msg)方法中,再一步步尋找
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) {
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);
}
// >>>>>>>>>>>>>>>
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
最終進(jìn)入到enqueueMessage方法,**msg.target = this; **這是綁定了當(dāng)前Handler到發(fā)送的這個Message的target屬性,最后調(diào)用的是MessageQueue的enqueueMessage方法,將消息放入到消息隊列中。
其中,sendMessageAtTime方法中,MessageQueue queue = mQueue;賦值MessageQueue,在Handler構(gòu)造方法中發(fā)現(xiàn) mQueue = mLooper.mQueue;也就是說MessageQueue和Looper有關(guān),我們再來看看Looper類。
先說說Looper是干什么的:Loop字面意思 回路 圈 。Looper類其實是用來循環(huán)取消息隊列中消息的,類中有個兩個主要的方法,prepare和loop方法,這里有的疑問好像要解開了,往下看
- 我們先來看看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方法是創(chuàng)建了Looper對象,同時設(shè)置給了sThreadLocal
sThreadLocal 是一個ThreadLocal對象。簡單點說,就是當(dāng)前Looper對象和當(dāng)前的線程對象關(guān)聯(lián)起來
仔細(xì)一看,"Only one Looper may be created per thread",沒錯,每個線程只允許一個Looper對象!
進(jìn)入Looper的構(gòu)造方法,很顯然,是在這里**MessageQueue被創(chuàng)建了 **
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
- 再來看看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;
// 省略部分代碼...
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
// 省略部分代碼...
try {
msg.target.dispatchMessage(msg);
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
// 省略部分代碼...
msg.recycleUnchecked();
}
}
源碼中Message msg = queue.next(); // might block 可以看到這個方法可能會阻塞,也就是說,消息隊列中沒有消息的時候會阻塞,這里是從消息隊列中取消息出來,調(diào)用個MessageQueue的next方法(具體的實現(xiàn)算法就不說了,包括入隊的算法,涉及到native層)有興趣的可以去看MessageQueue的源碼。
然后往下 msg.target.dispatchMessage(msg);這句代碼很好理解,前面我們說過在Handler發(fā)送消息的時候,會關(guān)聯(lián)當(dāng)前的Handler到所發(fā)送的Message的target屬性,這里看到就是調(diào)用Handler的dispatchMessage()方法,
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
方法很簡單,最終走的是handleMessage(msg);這行代碼,點過去看到是調(diào)用空方法,就是我們需要重寫的handleMessage方法。方法中我們還發(fā)現(xiàn)還可能會走h(yuǎn)andleCallback(msg);這行代碼,其實,這就是另一種情況,是利用Handler發(fā)送延時消息最后走的方法,請往下看。
二、延時發(fā)送一條消息
從Handler的postDelayed方法看起
public final boolean postDelayed(Runnable r, long delayMillis)
{
return sendMessageDelayed(getPostMessage(r), delayMillis);
}
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}
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);
}
最后調(diào)用的還是和上面分析發(fā)送一條消息時一樣,不過,這里多了一步getPostMessage,這是創(chuàng)建一個Message,并且賦值了Message的callback屬性,也就是我們在postDelayed方法中傳入的Runnable。
到這里,其實已經(jīng)分析結(jié)束了,Looper和MessageQueue分析如上,在Handler的dispatchMessage方法中執(zhí)行的是handleCallback(msg);因為msg.callback != null成立,最終,執(zhí)行的是Message的callback,也就是我們傳入的Runnable
private static void handleCallback(Message message) {
message.callback.run();
}
前面我們說了從Handler發(fā)送消息,然后進(jìn)入消息隊列,Looper再循環(huán)從MessageQueue中取出消息,最后執(zhí)行相應(yīng)的方法。細(xì)心的觀眾發(fā)現(xiàn),Handler我們可以自己new出來,Message可以obtain,MessageQueue是由Looper中生成的,那么Looper又是怎么初始化的呢?
這里涉及到了ActivityThread這個類,我們都知道,ActivityThread中的main方法是整個應(yīng)用進(jìn)程的入口。
查看源碼
public static void main(String[] args) {
// 省略代碼...
Looper.prepareMainLooper();
// 省略代碼...
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
看到了,Looper被初始化了,并且調(diào)用了loop,開始輪詢消息隊列。
解釋一下prepareMainLooper()和prepare方法有什么不同,就是true|false的區(qū)別,表示是否可以被終止,因為這是主線程的Looper,所以false.
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
有點恍然大悟的感覺,為什么主線程中可以更新UI控件了,原來是系統(tǒng)主線程中會主動初始化一個Looper(我們?nèi)绻謩釉賞repare就會報錯,因為每個線程只允許一個Looper,也確保我們可以在不同的線程中創(chuàng)建各自的Handler,進(jìn)行各自的通信而不會互相干擾)。那么,子線程中除了使用Handler或者調(diào)用runOnUiThread來更新UI控件,當(dāng)然也可以前后加上Looper.prepare();和Looper.loop();,不過實際開發(fā)中不會這么用。