最近決定把之前學習過的東西整理1遍,然后把寫得1些代碼review1遍,今天來學習1下消息機制,之前學過,沒太弄清楚,有很多都忘記得差不多了,終究到底還是自己用得太少了,要多實踐多實踐。
1、首先上圖(圖片來源于他人的博客,盜圖1枚)
從這張圖我們可以看到觸及到消息機制的1些類,比如Looper、Message、MessageQueue、Handler等,和里面的成員變量和方法。下面我們來學習1下這幾個類。
Message:
what : what this message is about.用戶自定義的消息碼,以便接受者可以辨認。每一個Handler 對消息碼有自己的命名空間,所以不用擔心和其他的handler沖突。在消息處理中,我們可以根據這個字段的不同的值進行不同的處理。
arg1和arg2 :這兩個參數是為了減小開消的替換物,就是你要是使用setData()寄存少數幾個整型數值的話。
obj : 發送給接收者的任意對象。當我們使用Messenger跨進程發送消息的時候,如果是Parcelable框架類的話必須是非空的。對1般的數據1般使用setData()傳遞。
target : 處理消息的handler。
when :消息甚么時候入隊列,甚么時候提交,甚么時候回收這樣的標志吧。
callback : handler發送消息的時候可以post1個runnable對象,會觸發回調。
next:下1個消息,看代碼我們知道消息是以鏈表1樣的情勢存儲的,而消息對列是以對列的方式處理消息,先進入的消息先處理。
obtain() : 推薦使用這樣的方式取得消息對象,效力會更高。
recycle() : 當消息處理完后,回收消息對象。
MessageQueue
MessageQueue類提供1個消息隊列,和插入、刪除和提取消息的函數接口。
mPtr : 通過這個變量保存1個Native層的NativeMessageQueue對象
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個線程最多只可以具有1個MessageQueue,安卓中通過ThreadLocal來保證1個線程中最多有1個Looper
Looper
Threads by default do not have a message loop associated with them.線程默許情況下是沒有消息循環的。實現Thread的消息循環和消息派發,缺省情況下Thread是沒有這個消息循環的既沒有Looper;
需要主動去創建,然后啟動Looper的消息循環loop;與外部的交互通過Handler進行;Looper 的構造函數很簡單,創建MessageQueue,保存當前線程到 mThread 中。但它是私有的,只能通過兩個靜態函數 prepare()/prepareMainLooper() 來調用。
mQueue : 消息對列
prepare() : 初始化當前線程作為Looper。在調用loop()之前1定要先履行這個方法。知道調用了quite這個方法。
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()
初始化當前線程為looper,并且使其作為程序的主looper。通常是由程序根據環境創建的,所以開發者不建議使用這個方法。
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()
取得當前線程的looper,sThreadLocal是 ThreadLocal sThreadLocal 。ThreadLocal保證了1個線程里面只有1個Looper對象。關于ThreadLocal的原理大家可以到網上找點資料看1下,有點類似根據id尋覓值。
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
loop()
這個類中最重要的1個方法。讓Looper開始工作,從消息隊列里取消息,處理消息。 Looper對象通過MessageQueue來寄存消息和事件。1個線程只能有1個Looper,對應1個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 : 線程的消息處理循環,其實不是每個線程都有消息處理循環。1般開發中用得比較多的是1個有Looper的Thread實現,HandlerThread。
mQueue : 消息對列對象,是成員對象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 的簡便途徑:只需實現回調接口 Callback,而無需子類化Handler。mAsynchronous 是標識是不是異步處理消息。
obtainMessage()
從消息池返回1個新的消息對象。實際上就是調用Message.obtain();
public final Message obtainMessage()
{
return Message.obtain(this);
}
boolean sendMessage(Message msg)
將消息push到消息對列里面所有等待消息的最后面,在規定的時間內,線程里面的handler會遭到這個消息。
public final boolean sendMessage(Message msg)
{
return sendMessageDelayed(msg, 0);
}
boolean post(Runnable r)
將Runnable對象添加到消息對列里面,這個Runnable對象將被該線程的handler處理。如果成功添加到消息對列里面的話返回true。失敗返回false,失敗通常是looper處理的這個消息正在對列中退出。
public final boolean post(Runnable r)
{
return sendMessageDelayed(getPostMessage(r), 0);
}
void dispatchMessage(Message msg)
顧名思義這個方法是處理消息的。會根據不同的條件調用不同的函數。在傳入的這個Message對象履行Message.obtain()的時候會對msg.callback進行賦值。
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
所以在查看消息處理對應的函數時,要看消息是不是是通過obtain()取得的,如果是那末消息處理就會交由傳遞參數中callback.run()來處理。而mCallback 則是在實例化Handler的時候初始化賦值的。如果msg.callback == null,且 mCallback == null,則由Handler本身的handleMessage()來處理。
**在判斷調用哪一個消息處理函數時,1定要先看是不是在調用obtain構造消息的時候是否是傳遞了msg或Runable參數,如果沒有,則判斷在構造Handler時是不是將
Callback 函數當作參數傳遞了進來,最后再看自己的Handler是不是重寫了handleMessage函數。**
void handleMessage(Message msg)
子類必須實現這個方法,去接收消息,然后再進行1些處理。
public void handleMessage(Message msg) {
}
**> MessageQueue作為1個容器,保存了所有待履行的消息。
MessageQueue中的Message包括3種類型:普通的同步消息,Sync barrier(target = null),異步消息(isAsynchronous() = true)。 MessageQueue的核心函數為enqueueMessage和next,前者用于向容器內添加Message,而Looper通過后者從MessageQueue中獲得消息,并實現無消息情況下的等待。 MessageQueue把Android消息機制的Java實現和C++實現聯系起來。 每一個線程最多可以有1個Looper。 每一個Looper有且唯一1個MessageQueue 每一個Handler關聯1個MessageQueue,由該MessageQueue關聯的Looper履行(調用Hanlder.dispatchMessage) 每一個MessageQueue可以關聯任意多個Handler Looper API的調用順序:Looper.prepare >> Looper.loop >> Looper.quit Looper的核心函數是Looper.loop,1般loop不會返回,直到線程退出,所以需要線程完成某個work時,請發送消息給Message(或說Handler)**