理一下Handler消息分發(fā)流程缨叫,一定離不開這幾個(gè)類:
Handler:用于消息發(fā)送和接收
Message:消息
MessageQueue:消息隊(duì)列算柳,用于存儲消息
Looper:循環(huán)取出從MessageQueue中的Message
分三點(diǎn)說起擂红,Handler的創(chuàng)建土砂、消息的發(fā)送乏悄、消息的接收
一龙亲、Handler的創(chuàng)建
首先從new Handler
開始看看Handler初始化的時(shí)候都做了什么:
//Handler源碼
public Handler(Callback callback, boolean async) {
...
mLooper = Looper.myLooper();
...
mQueue = mLooper.mQueue;
mCallback = callback;
...
}
內(nèi)容很簡單陕凹,mLooper、mQueue鳄炉、mCallback的賦值杜耙,mCallback沒什么說的,我們初始化的時(shí)候傳遞過來的:
private Handler handler = new Handler(new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
//消息處理
return false;
}
});
那這里的mLooper是怎么來的拂盯?而且mQueue的賦值也是取的mLooper.mQueue佑女,跟進(jìn)去這個(gè)Looper.myLooper()
方法:
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
關(guān)于ThreadLocal在Handler常見疑問的最后寫過了,這里需要疑問的是sThreadLocal什么時(shí)候set的。主線程的Looper是在ActivityThread中創(chuàng)建的团驱,ActivityThread是App一啟動就會調(diào)用的摸吠,去從ActivityThread的main方法開始跟起:
public static void main(String[] args) {
...
Looper.prepareMainLooper();
...
Looper.loop();
...
}
先跟這個(gè)prepareMainLooper()方法:
public static void prepareMainLooper() {
prepare(false);
...
}
...
private static void prepare(boolean quitAllowed) {
...
sThreadLocal.set(new Looper(quitAllowed));
}
到這里就已經(jīng)找到了主線程中Looper的創(chuàng)建,是在APP一啟動就創(chuàng)建了嚎花。然后再看看Looper.loop();
做了什么:
public static void loop() {
final Looper me = myLooper();
...
final MessageQueue queue = me.mQueue;
...
for (;;) {
Message msg = queue.next(); // might block
...
msg.target.dispatchMessage(msg);
...
msg.recycleUnchecked();
}
}
這里的for是一個(gè)無限循環(huán)寸痢,不斷的從MessageQueue中取出消息并且分發(fā),這段代碼先留著贩幻,一會到消息發(fā)送的時(shí)候再具體看轿腺,先看前兩句两嘴,獲取Looper并且獲取Looper中的MessageQueue丛楚,myLooper()
剛才看過了,還是調(diào)用sThreadLocal.get();
獲取的Looper對象憔辫,那MessageQueue是什么時(shí)候創(chuàng)建趣些,這里的me是個(gè)Looper的實(shí)例,那mQueue肯定是Looper的一個(gè)全局屬性贰您,mQueue是在Looper的構(gòu)造函數(shù)中賦值的:
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
這個(gè)牽扯出個(gè)跟主流程無關(guān)的問題坏平,構(gòu)造函數(shù)會發(fā)現(xiàn)是私有的,為什么這樣處理锦亦?那是怎么提供給外界的舶替?
上面其實(shí)已經(jīng)貼過了:
public static void prepare() {
prepare(true);
}
private static void prepare(boolean quitAllowed) {
...
sThreadLocal.set(new Looper(quitAllowed));
}
就是這個(gè)prepare()
方法,還是個(gè)靜態(tài)的杠园,在ActivityThread的main函數(shù)中調(diào)用了顾瞪,這個(gè)結(jié)合Handler常見疑問中的ThreadLocal介紹,就很容易理解了抛蚁,只要是同一個(gè)線程中陈醒,調(diào)用sThreadLocal.get();
獲取的就是同一個(gè)對象。這樣保證主線程中的Looper只有一個(gè)瞧甩,MessageQueue作為Looper的屬性肯定也只有一個(gè)钉跷。
總結(jié)一下new Handler其實(shí)很簡單:
- 得到當(dāng)前線程中的Looper對象(本篇以主線程為例)
- 得到Looper中的MessageQueue
- 接收調(diào)用者傳遞過來的Callback
到這里,必須理清楚的有:
- 主線程的Looper在App啟動的時(shí)候已經(jīng)創(chuàng)建好了肚逸,而MessageQueue作為Looper的全局屬性也已經(jīng)在構(gòu)造函數(shù)中創(chuàng)建了爷辙,并且Looper已經(jīng)開始無限循環(huán)從MessageQueue中取消息,雖然現(xiàn)在可能沒有消息
- Looper是通過
ThreadLocal.get()
獲取的朦促,所以線程唯一膝晾,而MessageQueue作為Looper的全局屬性也是線程唯一 - Handler創(chuàng)建之后已經(jīng)持有了當(dāng)前線程(本篇以主線程Handler為例)唯一的Looper、MessageQueue和調(diào)用者傳遞過來的Callback
二思灰、消息發(fā)送
Handler創(chuàng)建好之后玷犹,從消息的發(fā)送開始分析源碼,使用代碼:
new Thread(new Runnable() {
@Override
public void run() {
handler.sendMessage(handler.obtainMessage());
}
}).start();
直接點(diǎn)進(jìn)去sendMessage()
:
public final boolean sendMessage(Message msg)
{
return sendMessageDelayed(msg, 0);
}
public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
...
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
MessageQueue queue = mQueue;
...
return enqueueMessage(queue, msg, uptimeMillis);
}
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
...
return queue.enqueueMessage(msg, uptimeMillis);
}
這都是Handler里的方法,一路跟下來首先在sendMessageAtTime()
方法中獲取了MessageQueue為mQueue歹颓,這里先確定一下坯屿,雖然是在子線程調(diào)用的sendMessage()
方法,但是這個(gè)handler還是主線程中的handler巍扛,這個(gè)一定要清楚领跛,所以根據(jù)Handler創(chuàng)建過程的分析可以肯定這里的mQueue是主線程中的MessageQueue,然后在enqueueMessage ()
方法中撤奸,調(diào)用了queue.enqueueMessage()
把這個(gè)消息壓入了主線程的MessageQueue中吠昭,跟這個(gè)方法之前還有個(gè)注意點(diǎn)就是這個(gè)msg.target = this
,在壓入消息之前胧瓜,把handler本身設(shè)置給了msg矢棚,也就是msg也持有了hander,這個(gè)target只是取的一個(gè)名字府喳,他的類型就是Handler:
public final class Message implements Parcelable {
...
Handler target;
...
}
繼續(xù)到MessageQueue中跟上面的壓入方法queue.enqueueMessage()
:
boolean enqueueMessage(Message msg, long when) {
...
...
Message p = mMessages;
if (p == null || when == 0 || when < p.when) {
...
mMessages = msg;
...
} else {
// Inserted within the middle of the queue. Usually we don't have to wake
// up the event queue unless there is a barrier at the head of the queue
// and the message is the earliest asynchronous message in the queue.
...
}
...
}
這里的if...else...可以簡單理解為如果當(dāng)前隊(duì)列里沒有消息并且要發(fā)送的這個(gè)消息沒有延遲蒲肋,就直接賦值給mMessages,否則就加入到消息隊(duì)列中钝满。
我們跟流程這里不需要看那么復(fù)雜兜粘,就直接走if中的流程,也就是說我們要發(fā)送的這個(gè)消息已經(jīng)賦值給了MessageQueue的全局屬性mMessages弯蚜。
到這里消息發(fā)送流程完事孔轴,再總結(jié)一下上面的流程:
- 通過主線程的Handler發(fā)送一條message
- handler的
sendMessage()
方法最終是調(diào)用了queue.enqueueMessage(message, ...)
,并且這個(gè)message的target指向handler碎捺,這里的queue就是主線程的MessageQueue - MessageQueue的
enqueueMessage(message, ...)
方法接收到這個(gè)message并且復(fù)制給了自己的全局屬性mMessages
三路鹰、消息接收
private Handler handler = new Handler(new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
//消息處理
return false;
}
});
消息接收就是要看handler的handleMessage(Message msg)
上面時(shí)候被調(diào)用,也就是
handler什么時(shí)候收到回調(diào)牵寺。
在第一步Handler的創(chuàng)建的時(shí)候悍引,Loop里有一個(gè)無限循環(huán),就是從MessageQueue中取消息的帽氓,在第二步消息發(fā)送的時(shí)候已經(jīng)把Message放入了MessageQueue中(本篇流程設(shè)定場景是已經(jīng)把要發(fā)送的Message設(shè)置給了MessageQueue中的mMessages)趣斤。所以現(xiàn)在就從Looper.loop
這個(gè)無限循環(huán)開始看起,還是Handler創(chuàng)建時(shí)候跟到的這段代碼:
public static void loop() {
final Looper me = myLooper();
...
final MessageQueue queue = me.mQueue;
...
for (;;) {
Message msg = queue.next(); // might block
...
msg.target.dispatchMessage(msg);
...
msg.recycleUnchecked();
}
}
這里通過queue.next()
獲取到Message對象黎休,并切通過msg.target.dispatchMessage(msg)
發(fā)送消息浓领。先看queue.next()
代碼:
Message next() {
...
for (;;) {
...
synchronized (this) {
...
Message msg = mMessages;
...
if (msg != null) {
...
return msg;
...
} else {
...
}
...
}
}
這個(gè)next()
返回一個(gè)Message對象,而這個(gè)對象正是剛才發(fā)送消息時(shí)候賦值的mMessages势腮,這樣就是會說已經(jīng)拿到了剛才要發(fā)送的對象联贩。
這個(gè)函數(shù)里...的部分是非本篇邏輯的代碼,就是上面我們發(fā)送消息的時(shí)候沒考慮多條待處理消息和延遲消息捎拯,所以這里也不考慮MessageQueue消息堆積的邏輯泪幌,再解釋一下就是消息沒堆積,MessageQueue中只有一條,發(fā)送的時(shí)候賦值給mMessages祸泪,取的時(shí)候從mMessages里取吗浩。其實(shí)這里如果發(fā)送消息的時(shí)候發(fā)現(xiàn)mMessages有值會有另外的邏輯去存消息,取的時(shí)候也就需要相應(yīng)的邏輯去取没隘,本篇主要梳理Handler工作方式懂扼,不展開消息隊(duì)列的具體工作方式。
拿到消息之后是用過msg.target.dispatchMessage(msg);
發(fā)送的右蒲,而這個(gè)target上面分析過其實(shí)就是handler阀湿,直接去看Handler的dispatchMessage(msg)
的方法:
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)用了,也就是handler拿到了回調(diào)瑰妄,收到消息陷嘴,流程走完。
這個(gè)dispatchMessage()
方法還有要說的翰撑,這里發(fā)現(xiàn)有兩重if...else判斷罩旋,首先我們的message沒有設(shè)置callback,我們設(shè)置的是handler的callback眶诈,所以直接進(jìn)來第一次判斷的else里,這個(gè)問題在Handler常見疑問的Handler兩種創(chuàng)建方式里已經(jīng)寫的很明白瓜饥。那這個(gè)第一層if里的邏輯msg.callback
流程是怎么樣的逝撬?這就牽扯出了下一個(gè)問題
四、Handler的post()方法
new Thread(new Runnable() {
@Override
public void run() {
handler.post(new Runnable() {
@Override
public void run() {
Toast.makeText(MainActivity.this, "我是被post出來的吐司", Toast.LENGTH_LONG).show();
}
});
}
}).start();
這種使用也不陌生乓土,跟這個(gè)post()
方法看看:
public final boolean post(Runnable r)
{
return sendMessageDelayed(getPostMessage(r), 0);
}
看看這個(gè)getPostMessage(r)
對Runnable做了什么操作:
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}
他把Runnable封裝成了一個(gè)Message宪潮,并且返回,也就是說post (Runnable r)
方法把傳遞過來的Runnable封裝成了一個(gè)Message趣苏,然后調(diào)用了sendMessageDelayed(message, ...)
方法狡相,而這個(gè)Message的callback屬性指向了這個(gè)Runnable,關(guān)于sendMessageDelayed(message, ...)
方法不用繼續(xù)跟了食磕,上面消息發(fā)送的時(shí)候已經(jīng)分析的透透的了尽棕。到這里就可以繼續(xù)消息接收中的那個(gè)問題:
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
...
}
}
這里的if條件就是這樣進(jìn)來的,然后繼續(xù)下去這個(gè)handleCallback(msg);
彬伦,跟之前再說一下滔悉,這個(gè)msg的callback屬性是指向子線程中傳遞過來的一個(gè)Runnable,明確之后繼續(xù)跟handleCallback(msg)
:
private static void handleCallback(Message message) {
message.callback.run();
}
非常簡單单绑,就一句回官,調(diào)用了message中runnable的run()方法。結(jié)合上面的消息發(fā)送和接收搂橙,總結(jié)一下:
- 在子線程中通過handler.post(runnable)發(fā)送了一個(gè)Runnable對象
- 把這個(gè)Runnable對象封裝成Message對象放入到MessageQueue中
- 主線程的Looper對象在無限從MessageQueue中取消息歉提,會取出這個(gè)帶有Runnable的Message
- 取出后執(zhí)行Message對象中Runnable的
run()
方法
再仔細(xì)想一下這個(gè)post()方法,這就是Handler實(shí)現(xiàn)線程切換的流程,本例中Handler苔巨、Loop弯屈、MessageQueue都是主線程中的,子線程里把一個(gè)Runnable對象封裝成Message對象放入到主線程Loop對象的MessageQueue恋拷,直到這個(gè)Message被取出资厉,調(diào)用了message.runnable.run()
。