1遇八、定義
一套 Android 消息傳遞機(jī)制
2瘦赫、作用
在多線程的應(yīng)用場(chǎng)景中箕般,將工作線程中需更新 UI
的操作信息 傳遞到UI
主線程甸昏,從而實(shí)現(xiàn) 工作線程對(duì)UI的更新處理顽分,最終實(shí)現(xiàn)異步消息的處理
3、意義
- 問:為什么要用 Handler消息傳遞機(jī)制
- 答:多個(gè)線程并發(fā)更新UI的同時(shí) 保證線程安全
4施蜜、 相關(guān)概念
Handler 卒蘸、 Looper 、Message 翻默、MessageQueue都與Android異步消息處理線程相關(guān)的概念.
那么和Handler 悬秉、 Looper 、Message冰蘑、MessageQueue有啥關(guān)系和泌?其實(shí)Looper負(fù)責(zé)的就是創(chuàng)建一個(gè)MessageQueue,然后進(jìn)入一個(gè)無限循環(huán)體不斷從該MessageQueue中讀取消息祠肥,而消息的創(chuàng)建者就是一個(gè)或多個(gè)Handler 武氓。
主線程創(chuàng)建一個(gè)handler對(duì)象后維護(hù)一個(gè)Looper,Looper創(chuàng)建一個(gè)MessageQueue仇箱,通過死循環(huán)一直檢測(cè)MQ是否有消息進(jìn)來县恕,如果有通知handler處理消息,并且handler就是負(fù)責(zé)往MQ發(fā)消息的對(duì)象
5剂桥、 使用方式
-
Handler
的使用方式因 發(fā)送消息到消息隊(duì)列的方式不同而不同 - 共分為2種:使用
Handler.sendMessage()
忠烛、使用Handler.post()
6、 圖解
7权逗、 源碼分析
1.new Handler()
--->this(null, false);
--->Looper mLooper = Looper.myLooper();
--->MessageQueue mQueue = mLooper.mQueue
2.handler.sendMessage(message);
--->sendMessageAtTime()
--->enqueueMessage(queue, msg, uptimeMillis)
--->msg.target = this; --- Handler對(duì)象
--->queue.enqueueMessage(msg, uptimeMillis) -- 消息存到消息隊(duì)列
3.Looper
prepare():
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
new Looper():
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
注意:一個(gè)線程中只能有一個(gè)Looper對(duì)象美尸,只能有一個(gè)消息隊(duì)列MessageQueue
loop():
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Loop r; 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;
}
。斟薇。师坎。。
msg.target.dispatchMessage(msg); --- handler
}
4.handler.dispatchMessage():
if (msg.callback != null) {
handleCallback(msg); --- >回調(diào)自身Runnable中run方法堪滨,使用post方法的時(shí)候
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg); --- >子類必須重寫
}
回到最后處理的方法:
private static void handleCallback(Message message) {
message.callback.run();
}
/**
* Subclasses must implement this to receive messages.
*/
public void handleMessage(Message msg) {
}
4胯陋、 總結(jié)
Handler的構(gòu)造方法,會(huì)首先得到當(dāng)前線程中保存的Looper實(shí)例,進(jìn)而與Looper實(shí)例中的MessageQueue想關(guān)聯(lián)遏乔。
Handler的sendMessage方法义矛,會(huì)給msg的target賦值為handler自身,然后將Message加入MessageQueue中盟萨。
Looper.prepare()在本線程中保存一個(gè)Looper實(shí)例凉翻,然后該實(shí)例中保存一個(gè)MessageQueue對(duì)象;因?yàn)長ooper.prepare()在一個(gè)線程中只能調(diào)用一次鸯旁,所以MessageQueue在一個(gè)線程中只會(huì)存在一個(gè)噪矛。
Looper.loop()會(huì)讓當(dāng)前線程進(jìn)入一個(gè)無限循環(huán),從MessageQueue的實(shí)例中讀取消息铺罢,然后回調(diào)msg.target.dispatchMessage(msg)方法艇挨。
handler.dispatchMessage(msg)分發(fā)消息,如果是sendMessage()韭赘,會(huì)回調(diào)重寫的handleMessage方法缩滨;如果是post(),會(huì)最后會(huì)回調(diào) message.callback.run()泉瞻,當(dāng)前的run()方法脉漏。
在Activity中,我們并沒有顯示的調(diào)用Looper.prepare()和Looper.loop()方法袖牙,為啥Handler可以成功創(chuàng)建呢只磷,這是因?yàn)樵贏ctivity的啟動(dòng)代碼中悯恍,已經(jīng)在當(dāng)前UI線程調(diào)用了Looper.prepare()和Looper.loop()方法孵奶。
疑問:主線程死循環(huán)為什么不會(huì)卡死App槐臀?
真正會(huì)卡死主線程的操作是在回調(diào)方法onCreate/onStart/onResume等操作時(shí)間過長,會(huì)導(dǎo)致掉幀畴蹭,甚至發(fā)生ANR坦仍,looper.loop本身不會(huì)導(dǎo)致應(yīng)用卡死。