最近決定把之前學(xué)習(xí)過的東西整理1遍,然后把寫得1些代碼review1遍,今天來學(xué)習(xí)1下消息機(jī)制,之前學(xué)過,沒太弄清楚,有很多都忘記得差不多了,終究到底還是自己用得太少了,要多實(shí)踐多實(shí)踐。
1、首先上圖(圖片來源于他人的博客,盜圖1枚)
從這張圖我們可以看到觸及到消息機(jī)制的1些類,比如Looper、Message、MessageQueue、Handler等,和里面的成員變量和方法。下面我們來學(xué)習(xí)1下這幾個(gè)類。
Message:
what : what this message is about.用戶自定義的消息碼,以便接受者可以辨認(rèn)。每一個(gè)Handler 對(duì)消息碼有自己的命名空間,所以不用擔(dān)心和其他的handler沖突。在消息處理中,我們可以根據(jù)這個(gè)字段的不同的值進(jìn)行不同的處理。
arg1和arg2 :這兩個(gè)參數(shù)是為了減小開消的替換物,就是你要是使用setData()寄存少數(shù)幾個(gè)整型數(shù)值的話。
obj : 發(fā)送給接收者的任意對(duì)象。當(dāng)我們使用Messenger跨進(jìn)程發(fā)送消息的時(shí)候,如果是Parcelable框架類的話必須是非空的。對(duì)1般的數(shù)據(jù)1般使用setData()傳遞。
target : 處理消息的handler。
when :消息甚么時(shí)候入隊(duì)列,甚么時(shí)候提交,甚么時(shí)候回收這樣的標(biāo)志吧。
callback : handler發(fā)送消息的時(shí)候可以post1個(gè)runnable對(duì)象,會(huì)觸發(fā)回調(diào)。
next:下1個(gè)消息,看代碼我們知道消息是以鏈表1樣的情勢(shì)存儲(chǔ)的,而消息對(duì)列是以對(duì)列的方式處理消息,先進(jìn)入的消息先處理。
obtain() : 推薦使用這樣的方式取得消息對(duì)象,效力會(huì)更高。
recycle() : 當(dāng)消息處理完后,回收消息對(duì)象。
MessageQueue
MessageQueue類提供1個(gè)消息隊(duì)列,和插入、刪除和提取消息的函數(shù)接口。
mPtr : 通過這個(gè)變量保存1個(gè)Native層的NativeMessageQueue對(duì)象
mMessages : 保存接收到的Message消息。
mQuitAllowed: 是不是允許終止,如果允許的話該值為true。
void quit(boolean safe) {
if (!mQuitAllowed) {
throw new IllegalStateException("Main thread not allowed to quit.");
}
synchronized (this) {
if (mQuitting) {
return;
}
mQuitting = true;
if (safe) {
removeAllFutureMessagesLocked();
} else {
removeAllMessagesLocked();
}
// We can assume mPtr != 0 because mQuitting was previously false.
nativeWake(mPtr);
}
}
mQuitting : 是不是終止了。
private boolean isPollingLocked() {
// If the loop is quitting then it must not be idling.
// We can assume mPtr != 0 when mQuitting is false.
return !mQuitting && nativeIsPolling(mPtr);
}
mBlocked:是不是正在等待被激活以獲得消息。
1個(gè)線程最多只可以具有1個(gè)MessageQueue,安卓中通過ThreadLocal來保證1個(gè)線程中最多有1個(gè)Looper
Looper
Threads by default do not have a message loop associated with them.線程默許情況下是沒有消息循環(huán)的。實(shí)現(xiàn)Thread的消息循環(huán)和消息派發(fā),缺省情況下Thread是沒有這個(gè)消息循環(huán)的既沒有Looper;
需要主動(dòng)去創(chuàng)建,然后啟動(dòng)Looper的消息循環(huán)loop;與外部的交互通過Handler進(jìn)行;Looper 的構(gòu)造函數(shù)很簡單,創(chuàng)建MessageQueue,保存當(dāng)前線程到 mThread 中。但它是私有的,只能通過兩個(gè)靜態(tài)函數(shù) prepare()/prepareMainLooper() 來調(diào)用。
mQueue : 消息對(duì)列
prepare() : 初始化當(dāng)前線程作為Looper。在調(diào)用loop()之前1定要先履行這個(gè)方法。知道調(diào)用了quite這個(gè)方法。
This gives you a chance to create handlers that then reference
* this looper, before actually starting the loop. Be sure to call
* {@link #loop()} after calling this method, and end it by calling
* {@link #quit()}.
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));
}
void prepareMainLooper()
初始化當(dāng)前線程為looper,并且使其作為程序的主looper。通常是由程序根據(jù)環(huán)境創(chuàng)建的,所以開發(fā)者不建議使用這個(gè)方法。
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
myLooper()
取得當(dāng)前線程的looper,sThreadLocal是 ThreadLocal sThreadLocal 。ThreadLocal保證了1個(gè)線程里面只有1個(gè)Looper對(duì)象。關(guān)于ThreadLocal的原理大家可以到網(wǎng)上找點(diǎn)資料看1下,有點(diǎn)類似根據(jù)id尋覓值。
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
loop()
這個(gè)類中最重要的1個(gè)方法。讓Looper開始工作,從消息隊(duì)列里取消息,處理消息。 Looper對(duì)象通過MessageQueue來寄存消息和事件。1個(gè)線程只能有1個(gè)Looper,對(duì)應(yīng)1個(gè)MessageQueue。
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
final Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
}
final long traceTag = me.mTraceTag;
if (traceTag != 0) {
Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
}
try {
msg.target.dispatchMessage(msg);
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
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();
}
}
void quit()
Quits the looper
public void quit() {
mQueue.quit(false);
}
Handler
mLooper : 線程的消息處理循環(huán),其實(shí)不是每個(gè)線程都有消息處理循環(huán)。1般開發(fā)中用得比較多的是1個(gè)有Looper的Thread實(shí)現(xiàn),HandlerThread。
mQueue : 消息對(duì)列對(duì)象,是成員對(duì)象mLooper的成員變量。
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;
mCallback 提供了另外一種使用Handler 的簡便途徑:只需實(shí)現(xiàn)回調(diào)接口 Callback,而無需子類化Handler。mAsynchronous 是標(biāo)識(shí)是不是異步處理消息。
obtainMessage()
從消息池返回1個(gè)新的消息對(duì)象。實(shí)際上就是調(diào)用Message.obtain();
public final Message obtainMessage()
{
return Message.obtain(this);
}
boolean sendMessage(Message msg)
將消息push到消息對(duì)列里面所有等待消息的最后面,在規(guī)定的時(shí)間內(nèi),線程里面的handler會(huì)遭到這個(gè)消息。
public final boolean sendMessage(Message msg)
{
return sendMessageDelayed(msg, 0);
}
boolean post(Runnable r)
將Runnable對(duì)象添加到消息對(duì)列里面,這個(gè)Runnable對(duì)象將被該線程的handler處理。如果成功添加到消息對(duì)列里面的話返回true。失敗返回false,失敗通常是looper處理的這個(gè)消息正在對(duì)列中退出。
public final boolean post(Runnable r)
{
return sendMessageDelayed(getPostMessage(r), 0);
}
void dispatchMessage(Message msg)
顧名思義這個(gè)方法是處理消息的。會(huì)根據(jù)不同的條件調(diào)用不同的函數(shù)。在傳入的這個(gè)Message對(duì)象履行Message.obtain()的時(shí)候會(huì)對(duì)msg.callback進(jìn)行賦值。
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
所以在查看消息處理對(duì)應(yīng)的函數(shù)時(shí),要看消息是不是是通過obtain()取得的,如果是那末消息處理就會(huì)交由傳遞參數(shù)中callback.run()來處理。而mCallback 則是在實(shí)例化Handler的時(shí)候初始化賦值的。如果msg.callback == null,且 mCallback == null,則由Handler本身的handleMessage()來處理。
**在判斷調(diào)用哪一個(gè)消息處理函數(shù)時(shí),1定要先看是不是在調(diào)用obtain構(gòu)造消息的時(shí)候是否是傳遞了msg或Runable參數(shù),如果沒有,則判斷在構(gòu)造Handler時(shí)是不是將
Callback 函數(shù)當(dāng)作參數(shù)傳遞了進(jìn)來,最后再看自己的Handler是不是重寫了handleMessage函數(shù)。**
void handleMessage(Message msg)
子類必須實(shí)現(xiàn)這個(gè)方法,去接收消息,然后再進(jìn)行1些處理。
public void handleMessage(Message msg) {
}
**> MessageQueue作為1個(gè)容器,保存了所有待履行的消息。
MessageQueue中的Message包括3種類型:普通的同步消息,Sync barrier(target = null),異步消息(isAsynchronous() = true)。 MessageQueue的核心函數(shù)為enqueueMessage和next,前者用于向容器內(nèi)添加Message,而Looper通過后者從MessageQueue中獲得消息,并實(shí)現(xiàn)無消息情況下的等待。 MessageQueue把Android消息機(jī)制的Java實(shí)現(xiàn)和C++實(shí)現(xiàn)聯(lián)系起來。 每一個(gè)線程最多可以有1個(gè)Looper。 每一個(gè)Looper有且唯一1個(gè)MessageQueue 每一個(gè)Handler關(guān)聯(lián)1個(gè)MessageQueue,由該MessageQueue關(guān)聯(lián)的Looper履行(調(diào)用Hanlder.dispatchMessage) 每一個(gè)MessageQueue可以關(guān)聯(lián)任意多個(gè)Handler Looper API的調(diào)用順序:Looper.prepare >> Looper.loop >> Looper.quit Looper的核心函數(shù)是Looper.loop,1般loop不會(huì)返回,直到線程退出,所以需要線程完成某個(gè)work時(shí),請(qǐng)發(fā)送消息給Message(或說Handler)**