有關Handler機制原理的總結
Handler是執行緒與執行緒間進行通訊的一套機制。
Handler是常被開發者拿來更新UI的一種訊息處理機制,它的執行機制需要底層的Looper和MessageQueue的支撐。
一個Android應用程式被建立時就會建立一個程序,該程序用應用的包名作為程序名。該程序會啟動主執行緒ActivityThread,也叫做UI主執行緒,但有時需要做些耗時操作,為了不能夠去阻塞UI主執行緒的正常執行,我們將它放在子執行緒中進行操作,操作完成後需要繪製UI,但Android子執行緒不能直接操作UI執行緒的,所以通過Handler來進行通訊。
為什麼Android子執行緒不能直接操作主執行緒?Android UI執行緒不是執行緒安全的,如果多執行緒併發的話就會造成介面混亂,不可控的狀態。那為什麼不能讓主程式加上鎖機制,這樣就能夠執行緒安全了?可上鎖就會有造成訪問的邏輯變得很麻煩、很複雜,並且會阻塞其他執行緒的執行。綜上問題,Android採用單執行緒模型來處理UI操作。
Handler機制原理
Handler機制是由Looper和MessageQueue來構建訊息機制的。
MessageQueue:訊息佇列。雖然名為佇列,但事實上它的內部儲存結構並不是真正的佇列,而是採用單鏈表的資料結構來儲存訊息列表的,其中主要有插入enqueue()和從中拿走並刪除next()兩個方法。
Looper:訊息迴圈。MessageQueue來儲存訊息,Looper則是以無限迴圈的方式去查詢是否有新訊息,如有就去處理,若沒有就standby(等待)。一個執行緒建立Handler時首先需要建立Looper的,不然報錯:RuntimeException: No Looper; Looper.prepare() wasn't called on this thread,而且每個執行緒下只需要建立一個Looper,不然會報錯:RuntimeException: Only one Looper may be created per thread。
class TestThread extends Thread{ @Override public void run() { super.run(); Looper.prepare(); Handler handler = new Handler(){ @Override public void handleMessage(Message msg) { super.handleMessage(msg); //.... } }; Looper.loop(); } }
但是UI執行緒是不需要建立的,是因為ActivityTread建立時就初始化了Looper,所以在UI主執行緒就能直接使用Handler。
在特定的執行緒中Handler使用當前的Looper來構建訊息迴圈系統,那handler是如何獲取到當前執行緒的Looper的?是通過ThreadLocal來獲取每個執行緒的Looper的,ThreadLocal是一個執行緒內部的資料儲存類。它是一個泛型類,裡面有set()和get()兩個主要方法。有關ThreadLocal的瞭解可參考Blog:ThreadLocal
Handler通過send Message或者post去將訊息傳送到messageQueue中,會呼叫enqueueMessage()方法,而Message Queue的next()方法會將該訊息返回給Looper,Looper接收到訊息,就會處理--Looper就交由handler的dispatchMessage方法
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
Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
}
msg.target.dispatchMessage(msg);
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();
}
}
接著,handler的dispatchMessage方法最終會呼叫handlerMessage方法來處理訊息:
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
最後,就是我們經常見到的重寫handlerMessage方法去處理訊息及UI操作了。