android Looper Handler機制
在具體看原始碼之前,我已經知道了MyMessage中有一個成員變數Handler target來儲存handle,於是我寫一個簡易模擬程式。
考慮因素如下:
1、應用程式無論是哪個MyHandler sendMessage過來的,都可以用一個looper進行處理。
2、MyLooper要有不斷提取訊息和處理訊息的能力,那麼要繼承Thread。使用一個List list來儲存訊息,run方法不斷取和獲取MyMessage中的target,呼叫handlerMessage方法即可。
類圖大概是這樣的:
當你想強行加一些prepare、loop等函式的時候,你會覺得很雞肋。
而且考慮到多執行緒雖然用同一個MyLooper可行,但是每個執行緒的生命週期和處理的時間不一,不應該採用一個MyLooper物件。帶著一些疑問我們看看原始碼是怎麼寫的。
1、Handler如何獲取Looper中的訊息佇列
預設建構函式呼叫this(null, false);
Handler.java
public Handler(Callback callback, boolean async) {
...
mLooper = Looper.myLooper();
mQueue = mLooper.mQueue;
}
Looper.myLooper();是獲取當前執行緒的Looper物件,此物件有成員mQueue。
handle算了與訊息佇列聯絡起來了,方法sendMessage呼叫了enqueueMessage,將訊息放去佇列
Handler.java
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
...
return queue.enqueueMessage(msg, uptimeMillis);
}
2、那Looper是怎麼跟當前執行緒形成一對一關係的
Looper.java
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));
}
可見prepare就是為了建立Looper,然後與當前執行緒繫結。
Looper類中成員變數static final ThreadLocal sThreadLocal = new ThreadLocal(); 儲存著執行緒和對應looper物件。
之前handle建構函式的Looper.myLooper();語句,其實是
public static Looper myLooper() {
return sThreadLocal.get();
}
sThreadLocal.get(); 返回當前執行緒looper物件。
3、所以Looper中loop方法先要獲取當前執行緒looper物件,然後得其訊息佇列。
public static void loop() {
final Looper me = myLooper();
...
for (;;) {
Message msg = queue.next(); // might block
...
msg.target.dispatchMessage(msg);
...
msg.recycle();
}
}
4、Handle訊息處理順序
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
先msg的回撥方法,再就是handle自身回撥方法,最後是handleMessage方法.
自此我們瞭解了Looper Handle機制”是什麼”,但更值得思考的是”為什麼”。
5、一對一的對應關係可以採用組合的方式實現,即執行緒裡面有Looper成員變數,應思考設計中的高內聚低耦合