?????為了深入了解Handler翘骂,我們對Handler進(jìn)行源碼分析壁熄,看看它究竟是如何完成線程間通信的。
從Handler構(gòu)造出發(fā)
?????既然是源碼分析碳竟,為什么突然回到Handler的構(gòu)造了呢草丧?在我的Handler使用機(jī)制及四個(gè)組成部分文章中,當(dāng)我們在非主線程創(chuàng)建handler對象時(shí)會(huì)出現(xiàn)一個(gè)異常莹桅。如下:
05-30 15:26:07.490 711-773/com.perry.handler E/AndroidRuntime: FATAL EXCEPTION: Thread-18868
Process: com.perry.handler, PID: 711
java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
at android.os.Handler.<init>(Handler.java:209)
at android.os.Handler.<init>(Handler.java:123)
at com.perry.handler.OnBackgroundActivity$2.run(OnBackgroundActivity.java:71)
at java.lang.Thread.run(Thread.java:818)
?????出現(xiàn)這個(gè)問題實(shí)際上是因?yàn)椴矗琱andler需要Looper對象烛亦,來進(jìn)行內(nèi)部的全局變量的初始化。
public Handler(Callback callback, boolean async)
public Handler(Looper looper, Callback callback, boolean async) {
mLooper = looper;
mQueue = looper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
?????通過查看源碼發(fā)現(xiàn)懂拾,handler共7個(gè)構(gòu)造函數(shù)煤禽,使用時(shí)只能使用4個(gè),最后都會(huì)調(diào)用執(zhí)行如上2個(gè)構(gòu)造方法岖赋,而這2個(gè)構(gòu)造方法大同小異檬果,所以我們挑個(gè)簡短的來看看。發(fā)現(xiàn)handler需要looper對象來初始化全局變量Looper及MessageQueue唐断,而MessageQueue是從looper中取出的选脊。MessageQueue用于進(jìn)程間傳遞消息,Looper則在該線程內(nèi)進(jìn)行消息的派發(fā)脸甘。
handler.sendMessage
?????我們通過構(gòu)造找到了handler的2個(gè)協(xié)同者恳啥,Looper與MessageQueue。那我們發(fā)個(gè)消息丹诀,看看他們都做了些什么6鄣摹?
?????無論調(diào)用post方法還是sendMessage方法铆遭,handler都會(huì)從上到下依次調(diào)用如下方法硝桩。
sendMessageDelayed(Message msg, long delayMillis)
sendMessageAtTime(Message msg, long uptimeMillis)
enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis)
handler.enqueueMessage
?????此時(shí),到了enqueueMessage方法疚脐,就證明這條消息確實(shí)發(fā)送了亿柑,該做下一步處理。
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
?????該方法中對message設(shè)置了target棍弄,將當(dāng)前的handler存于message中,用于之后message找到自己該去的handler疟游,而后將massage交給MessageQueue呼畸。調(diào)用queue.enqueueMessage(msg, uptimeMillis)方法,將消息放入到消息隊(duì)列中颁虐。強(qiáng)調(diào)一下蛮原,這里的queue就是我們前面說到的在構(gòu)造方法中從looper中取到的消息隊(duì)列。
Looper.loop()
?????到了這里另绩,我們發(fā)現(xiàn)handler將消息通過MessageQueue放入到消息隊(duì)列中儒陨,那誰把消息取出來進(jìn)行派發(fā)的呢?草叢三兄弟笋籽,跳出來兩個(gè)了蹦漠,還剩Looper一人默默的蹲在那,那我們來看看他究竟干了啥车海?笛园!
public static void loop() {
final Looper me = myLooper();
final MessageQueue queue = me.mQueue;
for (;;) {
Message msg = queue.next(); // might block 取出消息爷狈,無消息則阻塞
if (msg == null) {
// No message indicates that the message queue is quitting. 沒有消息則表明,消息隊(duì)列正在退出辫呻。
return;
}
msg.target.dispatchMessage(msg); // 發(fā)送消息劳较, 其中target就是我們之前存入的Handler
}
}
?????精簡了一下該方法,可以看到棵红,Looper通過loop方法凶赁,不停的從MessageQueue中取出消息,最終調(diào)用了handler的dispatchMessage(msg)方法將消息派發(fā)給handler自己逆甜。
handler.dispatchMessage
?????最后哟冬,消息派發(fā)給handler,會(huì)先判斷msg的callback對象(實(shí)際上是runnable對象)是否為空忆绰,如果不為空則執(zhí)行handleCallback(msg)方法浩峡,callback.run();而如果為空就會(huì)調(diào)用handleMessage方法,完成回調(diào)错敢。(這也是為什么我們構(gòu)造Handler時(shí)翰灾,實(shí)現(xiàn)了抽象方法handleMessage而post(runnable)時(shí),為什么不調(diào)用handleMessage方法的原因)稚茅。
// msg.callback實(shí)際上是Runnable對象
// mCallback是一個(gè)實(shí)現(xiàn)了handleMessage(msg)的回調(diào)接口
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg); // msg.callback.run();
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
?????那么來畫個(gè)圖總結(jié)一下纸淮。
?????圖中我們從主線程中創(chuàng)建Handler,在子線程中發(fā)送消息亚享,而這一系列的配合操作咽块,需要仔細(xì)看圖,不懂的可以回看文章欺税。
?????上一篇:Handler使用機(jī)制及四個(gè)組成部分