Handler、Looper、Message、MessageQueue這四者的關(guān)系,用比較通俗的方式解釋,可以理解為:Looper是傳送帶在不停的運(yùn)送貨物,MessageQueue是傳送帶上面的貨物隊(duì)列,Message就是貨物隊(duì)列中一個(gè)一個(gè)的貨物,而Handler則是貨物被消費(fèi)的地方。
Looper的分析
Looper是整個(gè)消息機(jī)制的關(guān)鍵節(jié)點(diǎn),Looper類用來(lái)為一個(gè)線程開啟一個(gè)消息循環(huán)。主線程是默認(rèn)開啟的,但是新的線程是默認(rèn)不開啟的,所以我們使用Handler從主線程或其他線程往子線程發(fā)消息,是會(huì)拋出沒(méi)有Looper對(duì)象這個(gè)錯(cuò)誤,這里我們?nèi)绻胪泳€程發(fā)送消息,那么必須在子線程中調(diào)用Looper.prepar()啟動(dòng)Looper,然后再調(diào)用Looper.loop()讓Looper開始工作。每個(gè)Looper都有與之對(duì)應(yīng)的MessageQueue當(dāng)執(zhí)行Looper.loop后MessageQueue的消息就開始被處理了。這里需要注意的是,Looper.loop是一個(gè)循環(huán),當(dāng)有消息時(shí)處理消息,沒(méi)有消息時(shí)掛起。所以Looper.loop之后的代碼是無(wú)法運(yùn)行的。如過(guò)需要運(yùn)行之后的代碼,需要執(zhí)行當(dāng)前線程的handler.getLooper.quit()使Looper退出消息處理,循環(huán)結(jié)束后面代碼就可以運(yùn)行了。
Looper和Handler、Message、MessageQueue的關(guān)系
要想了解Looper和Handler、Message、MessageQueue的關(guān)系我們最好能從源碼的角度將發(fā)送消息到消息隊(duì)列再到分發(fā)處理消息的整個(gè)流程重新走一邊。
- 首先創(chuàng)建的是Looper我們這里看下Looper的構(gòu)造方法:
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
這里可以看到當(dāng)啟動(dòng)了Looper后會(huì)創(chuàng)建一個(gè)MessageQueue與之綁定,并且綁定當(dāng)前線程。
有了Looper這個(gè)傳送帶和MessageQueue這個(gè)貨物隊(duì)列,我們?cè)倏纯窗l(fā)送與收取貨物的Handler的構(gòu)造方法:
空參的構(gòu)造函數(shù)執(zhí)行了 this(null, false);所以也就是執(zhí)行了Handler(Callback callback, boolean async)這個(gè)構(gòu)造函數(shù)下面我們看這個(gè)構(gòu)造函數(shù)
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;
}
在Handler中的構(gòu)造方法中上面那個(gè)if是打印內(nèi)存泄漏的日志, Looper.myLooper()用來(lái)獲取當(dāng)前線程的Looper對(duì)象,如果沒(méi)有則拋出錯(cuò)誤,就是Looper分析中提到的沒(méi)有Looper對(duì)象的問(wèn)題,解決方法也在那段中說(shuō)明了,下面再通過(guò)mLooper.mQueue獲取當(dāng)前線程的MessageQueue對(duì)象。下面我們有了Looper這個(gè)對(duì)象就可以以他為基礎(chǔ)通過(guò)Handler進(jìn)行通訊了。
Handler發(fā)送消息時(shí)可以設(shè)置不同的參數(shù),設(shè)置延時(shí)發(fā)送等等很多種方法,但是最后都會(huì)走到這段代碼:
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);
}
從這段代碼我們可以看到,msg被添加到由了構(gòu)造函數(shù)傳入的MessageQueue中,最后執(zhí)行了enqueueMessage(queue, msg, uptimeMillis)方法進(jìn)入MessageQueue隊(duì)列 :
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
注意這段代碼中的這句:msg.target = this;這句代碼表明這個(gè)msg的target的明確就是this也就是本類,所以后面消息分發(fā)時(shí)也會(huì)分發(fā)到這個(gè)target就是本類。
現(xiàn)在消息已經(jīng)傳遞到了Looper中,下面我們看看在Looper中消息是怎么分發(fā)的。
Looper中的消息分發(fā)的關(guān)鍵是loop()方法,下面看看這個(gè)方法的源碼:
/**
* 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
Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
}
msg.target.dispatchMessage(msg);
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();
}
}
從上面代碼中可以明顯看到幾個(gè)關(guān)鍵方法
- queue.next():在死循環(huán)中,不斷的通過(guò)queue.next獲取消息,
- msg.target.dispatchMessage(msg) :注意這里的target就是上面我們分析的那個(gè)target即發(fā)送消息的那個(gè)Handler對(duì)象,這里將消息隊(duì)列中的消息進(jìn)行了分發(fā)。
- msg.recycleUnchecked():這個(gè)方法是當(dāng)消息被分發(fā)掉,對(duì)消息進(jìn)行正在使用的標(biāo)記。
消息已經(jīng)分發(fā)完了,下面又回到了,Hanlder中處理消息了,那么我們常用的handler.handleMessage(msg)方法又是什么時(shí)候調(diào)用的呢,在上面那段的第2個(gè)關(guān)鍵方法msg.target.dispatchMessage(msg) 這個(gè)方法其實(shí)就是調(diào)用了target中的dispatchMessage()方法,這個(gè)target就是handler,所以我么再回到Handler的源碼中,看看這個(gè)dispatchMessage()是怎么接收消息的:
/**
* 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);
}
}
從這段代碼中,可以明確的看到執(zhí)行了handleMessage(msg)這個(gè)方法,到此整個(gè)消息發(fā)送到接收的流程已經(jīng)全部結(jié)束了。
總結(jié)
通過(guò)以上的分析可以知道 Looper.loop()不斷地獲取MessageQueue中的Message,然后調(diào)用與Message綁定的Handler對(duì)象的dispatchMessage方法,最后handleMessage就在dispatchMessage方法里被調(diào)用了。從這些源碼中可以看到,不同的handler對(duì)象可以設(shè)置不同的target消息也會(huì)分發(fā)到不同的handleMessage方法中,所以可以得出結(jié)論,Looper可以有多個(gè)handler與之綁定并向他發(fā)送消息,但是只能有一個(gè)對(duì)應(yīng)的線程,同時(shí)也只能有一個(gè)MessageQueue。