好久沒寫博客,實在沒得寫。。。但是項目中用到了Handler去做僞遞歸用來判斷AsyncTask是否finished
就對消息機制有了研究的興趣,看了好久的SDK sources中的源碼
現在寫一個消息機制的系列,如有錯誤或不足,請指正,必修改。
啥叫僞遞歸呢 就是在Handler對象的handleMessage方法中,如果AsyncTask的getStatus 方法返回的不是
AsyncTask.Status.FINISHED,就sendEmptyMessage給自己。
因爲知道Looper處理消息用的是loop方法 這個方法是在當前線程中執行的,也就是同步執行,所以好奇爲什麼沒有出現
ANR,我當時還用一個while 不斷的判斷AsyncTask的這個狀態,但是直接出現了ANR。
後來才知道發送消息之後只會將這個Message插入到MessageQueue中,即單鏈表插入。並沒有立即執行loop方法
如果是主線程的Looper,會在主線程每次循環最後 執行Looper.loop();
雖然這樣做並不算是即時的,但是延遲特別小 忽略不計了。。
聊入正題 ----Message
這是消息的載體,要介紹的內容也比較少(當作很久沒寫東西的過渡吧)
下面看Message的構造,
Message msg = new Message();
這是調用Message無參數的構造方法:
/**
* Constructor (but the preferred way to get a Message is to call {@link #obtain() Message.obtain()}).
*/
public Message() {
}
上面寫更好的構造一個Message的方法是obtain() ,
/**
* 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();
}
大家有沒有注意到了這個sPool, 它就是一個Message,如果它不爲null,就返回它作爲我們的Message,爲null就new 一個返回
那麼它在什麼時候創建呢,還有爲什麼有它呢?
我找到了 recycleUchecked() 方法,這個方法在Looper.loop() 中調用,即處理完這個消息後被調用,看loop() 的實現:
/**
* 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;
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;
}
........
msg.target.dispatchMessage(msg);
.........
msg.recycleUnchecked(); // 消息通過dispatchMessage處理之後,就去回收它
}
}
主要實現在recycleUchecked() 方法:這個方法會回收一個Message 而且這個Message的狀態可能是正在使用
而且由於沒有權限修飾符,我們直接創建的Message對象調用不了這個方法
/**
* Recycles a Message that may be in-use.
* Used internally by the MessageQueue and Looper when disposing of queued Messages.
*/
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 = -1;
when = 0;
target = null;
callback = null;
data = null;
synchronized (sPoolSync) {
if (sPoolSize < MAX_POOL_SIZE) {
next = sPool;
sPool = this;
sPoolSize++;
}
}
}
sPool = this; 這句話表示將調用了recycle方法的Message對象賦值給 sPool,這就解釋了爲什麼用obtain方法更好了
obtain() 會去 使用 被回收了 的Message,這樣就避免了創建很多個Message,一種節約資源的做法
obtain() 會去 使用 被回收了 的Message,這樣就避免了創建很多個Message,一種節約資源的做法
說起Message的作用,就是MessageQueue中單鏈表中的一個消息,它能幹嘛呢 ?
當Handler的把一條消息發送添加到MessageQueue後,之後當Looper.loop()被調用的時候 就會去處理這個消息 ,
看代碼,這是Looper.loop()方法內部
msg.target 是一個Handler 對象,即當初發送它的Handler,現在通過這個target.dispatchMessage()方法將消息又扔回給Handler處理,
看下dispatchMessage(),這個方法在Handler中:
/**
* 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);
}
}
這個callback 是Message的一個Runnable對象,如果沒傳,就不會執行它,最後是調用了handleMessage 方法
當然還有很多細節沒說,比如MessageQueue的管理,和Looper , Handler 的創建過程等等
這些以後再寫。。。。。。。