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發訊息執行的。