Android的Handler消息機制
實現原理
- 主線程會自動調用Looper.prepareMainLooper和Looper.loop,具體是在ActivityThread中main方法中調用的。
public static void main(String[] args) {
......省略無關代碼
// 主線程的Looper相關準備工做
Looper.prepareMainLooper();
// Find the value for {@link
// It will be in the format "seq=114"
long startSeq = 0;
if (args != null) {
for (int i = args.length - 1; i >= 0; --i) {
if (args[i] != null && args[i].startsWith(PROC_START_SEQ_IDENT)) {
startSeq = Long.parseLong(
args[i].substring(PROC_START_SEQ_IDENT.length()));
}
}
}
// 生成主線程
ActivityThread thread = new ActivityThread();
thread.attach(false, startSeq);
// 拿到主線程的Handler,並將主線程的Looper綁定到Handler中
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
// End of event ActivityThreadMain.
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
// 開啓消息循環
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
複製代碼
- 子線程使用Handler時,首先須要調用Looper.prepare,prepare方法中,new一個Looper對象,存入ThreadLocal;在Looper的構造中,會new一個MessageQueue,綁定到當前Looper中。
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
// new一個Looper對象
sThreadLocal.set(new Looper(quitAllowed));
}
private Looper(boolean quitAllowed) {
// new一個MessageQueue,綁定到Looper中
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
複製代碼
- 建立Handler實例,在Handler構造中,若傳入Looper,則將傳入的Looper綁定給Handler的Looper,並將傳入Looper的MessageQueue也綁定給Handler的MessageQueue。若不傳入Looper,則構造中,直接取當前線程的Looper以及該Looper的MessageQueue和handler綁定。
// 建立Handler選擇無參構造,會走到這裏
public Handler(Callback callback, boolean async) {
if (FIND_POTENTIAL_LEAKS) {
final Class<? extends Handler> klass = getClass();
if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
(klass.getModifiers() & Modifier.STATIC) == 0) {
Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
klass.getCanonicalName());
}
}
// 拿到當前線程的Looper,綁定到Handler中
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread " + Thread.currentThread()
+ " that has not called Looper.prepare()");
}
// 拿到當前線程Looper的MessageQueue,綁定到Handler中
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
// 建立Handler選擇有參構造,會走到這裏
public Handler(Looper looper, Callback callback, boolean async) {
// 將傳入的Looper以及該Looper的MessageQueue綁定到Handler中,讓Handler在Looper所在的線程環境中
mLooper = looper;
mQueue = looper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
複製代碼
- 接着調用Looper.loop,拿到myLooper,也就是從ThreadLocal中取,在拿到myLooper的MessageQueue,對MessageQueue死循環,MessageQueue.next()獲取消息,沒有消息則掛載。有消息時,會調用message的target的dispatchMessage方法分發消息。dispatchMessage方法中,首先判斷message是否有回調,有則直接將新消息傳遞給回調接口的run方法中。若message沒有回調,則再判斷handler是否有回調,有回調,則將新消息傳遞給回調接口的handleMessage方法中。若handler也沒有回調,則將消息傳遞給handler的handleMessage公開方法中。外部重寫該方法便可接收處理新消息。
public static void loop() {
// 拿到Looper
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
// 拿到Looper的MessageQueue
final MessageQueue queue = me.mQueue;
......省略無關代碼
// 對MessageQueue死循環
for (;;) {
// MessageQueue.next()獲取消息
Message msg = queue.next(); // might block
// 沒有消息則掛載
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
......省略無關代碼
try {
// 有消息時,調用message的target的dispatchMessage方法分發消息
msg.target.dispatchMessage(msg);
dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
......省略無關代碼
msg.recycleUnchecked();
}
}
// Handler分發消息
public void dispatchMessage(Message msg) {
// Message有回調,則直接將新消息傳遞給回調接口的run方法中
if (msg.callback != null) {
handleCallback(msg);
} else {
// Handler有回調,則將新消息傳遞給回調接口的handleMessage方法中
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
// 將消息傳遞給handler的handleMessage公開方法中
handleMessage(msg);
}
}
複製代碼
- hander.sendMessage,會調用enqueueMessage方法,將當前handler賦值給Message的target,而後調用handler的MessageQueue的enqueueMessage方法,內部會將新的message添加進MessageQueue中。此時,Looper中MessageQueue會被喚醒,循環獲取到新消息作下一步處理。
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
// 將當前handler賦值給Message的target
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
// 調用MessageQueue的enqueueMessage方法,內部會將新的message添加進MessageQueue鏈表中
return queue.enqueueMessage(msg, uptimeMillis);
}
複製代碼
相關概念
- 一個線程對應一個Looper,一個Looper對應一個MessageQueue,一個Looper可對應多個Handler,一個Handler對應一個Looper。
- 主線程中,MessageQueue死循環,並不會卡死UI。在ActivityThread的main方法中,首先調用Looper.prepareMainLooper,緊接着就會new一個ActivityThread,而且拿到該主線程的mainThreadHandler,再調用Looper的loop開啓消息循環。之後UI線程的UI刷新等操做也是在mainThreadHandler發消息執行的。