Message入列
判斷新創建Message處于隊列中的位置,并插入相應位置
//截取自MessageQueue.enqueueMessage()方法來舉例(刪除了部分與此次無關代碼)
boolean enqueueMessage(Message msg, long when) {
synchronized (this) {
//標記傳入的msg被使用
msg.markInUse();
msg.when = when;
//創建臨時變量來儲存消息隊列中的Message對象
Message p = mMessages;
boolean needWake;
/*
* 當消息隊列中沒有消息
* 或傳入Message的觸發時間為0時
* 或傳入Message的觸發時間小于當前消息隊列中的Message的觸發時間
*/
if (p == null || when == 0 || when < p.when) {
//把傳入的Message放入當前消息隊列中的Message之前
msg.next = p;
//把當前消息隊列中的Message對象重置為傳入的Message對象
mMessages = msg;
needWake = mBlocked;
} else {
/*
* 當消息隊列中有消息
* 且傳入Message的觸發時間不為0時
* 且傳入Message的觸發時間大于當前消息隊列中的Message的觸發時間
*/
needWake = mBlocked && p.target == null && msg.isAsynchronous();
//創建一個臨時變量
Message prev;
for (;;) {
//儲存臨時變量p(當前消息隊列中的Messge)
prev = p;
//讓p指向自己在消息隊列中的下一條消息
p = p.next;
//當p為null時,說明prev是當前消息隊列中的最后一條消息
//或者傳入Message的觸發時間小于p的觸發時間時終止循環
if (p == null || when < p.when) {
break;
}
}
/* 此時的p滿足以下兩個條件中的一個:
* 1.p為null時,說明prev是當前消息隊列中的最后一條消息(因為p為null,所以prev不為
null且prev的觸發時間小于傳入Message的觸發時間,所以傳入Message的為消息隊列中的最
后一條消息,prev為傳入Message的上一條消息)
* 2.p的觸發時間大于傳入Message的觸發時間(因為p的觸發時間大于傳入Message的觸發時
間,所以p在消息隊列中是傳入Message的下一條消息,因為在上一次循環中沒有進入if語句,
所以prev不為null且觸發時間小于傳入Message對象的觸發時間,所以prev在消息隊列中處于
傳入Message的上一條)
*/
msg.next = p;
prev.next = msg;
}
}
return true;
}
Message的獲取方式
Message的獲取方式除了new Message這種方式,Message類還提供了obtain方法來獲取Message
//Message類中有一個靜態全局變量來儲存空閑或者回收的Message對象
private static Message sPool;
public static Message obtain() {
synchronized (sPoolSync) {
if (sPool != null) {
Message m = sPool;
sPool = m.next;
m.next = null;
m.flags = 0;
sPoolSize--;
return m;
}
}
return new Message();
}
這種方式是把靜態全局變量sPool(這里可以把這個Message看做當前消息池中的第一條消息)標記為未使用然后返回,如果sPool為null才會創建新的Message對象,這樣不會造成資源的浪費,避免創建太多Message對象。關于為什么sPool會是被回收的Message對象,上源碼:
//此方法為Message的回收方法
public void recycle() {
//在回收的方法
recycleUnchecked();
};
void recycleUnchecked() {
//這里在做一些重置的工作
flags = FLAG_IN_USE;
what = 0;
arg1 = 0;
arg2 = 0;
obj = null;
replyTo = null;
sendingUid = -1;
when = 0;
target = null;
callback = null;
data = null;
synchronized (sPoolSync) {
//當消息池里消息的數量小于消息池的最大容量時
if (sPoolSize < MAX_POOL_SIZE) {
//重點!!!
/*把當前消息池中第一條消息(也就是sPool)置為當前消息的下一條消息(sPool為
全局靜態變量,所有Message都共用這一個sPool)*/
next = sPool;
/*把當前消息置為消息池中第一條消息(因為上一步驟已經把原來消息池中的第一條消息置為
了當前消息的下一條消息,現在把當前消息置為消息池中的第一條消息,所以sPool永遠代表
消息池中的第一條消息)*/
sPool = this;
sPoolSize++;
}
}
}
可以看出Message在回收過程中,只要消息池的數量小于消息池的最大容量時,就是把當前Message放入消息池中。
Message在MessageQueue隊列中存在的形式
從Message入列方式我們也看出,再有新消息進入隊列時,是先判斷新消息的觸發時間,找出消息應該插入消息隊列的位置,把這個位置的消息的next置為本條新消息,然后把新消息的next置為這個位置的消息的下一條消息。類似以下結構(如果我理解有錯,歡迎指出)。

message
系列目錄: