1. Message的重要屬性
Each Handler has its own name-space for message codes, so you do not need to worry about yours conflicting with other handlers. 每個Handler都有自己命名空間的消息碼,這樣不必擔心和其它Handler衝突。
每個Handler只處理自家的Message, 但Message是如何區分Handler呢?
這就需要我們考慮去將Message 和 Handler 進行綁定。
我們查看Message的源碼,會發現有一個成員變量:
Handler target;
當我們查看Message中各個obtain()方法,都會發現與target進行綁定(特殊的obtain()可以進一步查看Handler,其最終也是要對target進行綁定的,這裏不再展開)。
public static Message obtain(Handler h, int what,
int arg1, int arg2, Object obj) {
Message m = obtain();
m.target = h;
m.what = what;
m.arg1 = arg1;
m.arg2 = arg2;
m.obj = obj;
return m;
}
除了target ,還有:
Runnable callback
public long when;
關於Handler的更多詳情 Handler的前世今生4——Handler
2. Message 的obtain()
官方建議我們在發送消息儘量使用obtain(),我們來看一下obtain()的實現:
從全局的消息池中給我們返回一個新的Message實例,很多情況下可以避免我們新建對象。
/**
* Return a new Message instance from the global pool. Allows us to
* avoid allocating new objects in many cases.
*/
public static Message obtain() {
synchronized (sPoolSync) {
if (sPool != null) {
Message m = sPool;
sPool = m.next;
m.next = null;
m.flags = 0; // clear in-use flag
sPoolSize--;
return m;
}
}
return new Message();
我們通過進一步的分析Message的成員變量:
Message next;
private static Message sPool;
public static final Object sPoolSync = new Object(); // 全局鎖對象
private static int sPoolSize = 0;
private static final int MAX_POOL_SIZE = 50;
這就告訴我們,Message是鏈表設計,Message池的最大數量爲50.
3. Message的回收
FLAG_IN_USE 標記消息在使用中,當消息進入隊列或者複用時都被被置爲該狀態。
/** If set message is in use.
* This flag is set when the message is enqueued and remains set while it
* is delivered and afterwards when it is recycled. The flag is only cleared
* when a new message is created or obtained since that is the only time that
* applications are allowed to modify the contents of the message.
*
* It is an error to attempt to enqueue or recycle a message that is already in use.
*/
static final int FLAG_IN_USE = 1 << 0;
recyclerUnchecked()方法是用來複用消息的。這裏主要就是對消息的屬性恢復默認,其判斷消息池是否溢出。我們在Looper的loop()方法看過它的身影。
/**
* Recycles a Message that may be in-use.
* Used internally by the MessageQueue and Looper when disposing of queued Messages.
*/
@UnsupportedAppUsage
void recycleUnchecked() {
// Mark the message as in use while it remains in the recycled object pool.
// Clear out all other details.
flags = FLAG_IN_USE;
what = 0;
arg1 = 0;
arg2 = 0;
obj = null;
replyTo = null;
sendingUid = UID_NONE;
workSourceUid = UID_NONE;
when = 0;
target = null;
callback = null;
data = null;
synchronized (sPoolSync) {
if (sPoolSize < MAX_POOL_SIZE) {
next = sPool;
sPool = this;
sPoolSize++;
}
}
}
我們還看到一個recycle() 方法:
public void recycle() {
if (isInUse()) {
if (gCheckRecycle) {
throw new IllegalStateException("This message cannot be recycled because it "
+ "is still in use.");
}
return;
}
recycleUnchecked();
}
有沒有似曾相識的感覺,你在處理Bitmap時…(PS:Bitmap類中也有一個recycle()方法)。在涉及到複用的情況下,基本都會出現該方法的身影。
爲什麼Looper的loop()方法調用的是recycleUnchecked()呢?
個人認爲是:loop()中可以保證消息一定沒有在使用,完全沒有必要判斷isInUse(),所以直接調用了recycleUnchecked()。
OK ,關於Message的內容就介紹到這裏…
歡迎繼續收看 Handler的前世今生4 —— Handler