Android的Handler消息機(jī)制
實(shí)現(xiàn)原理
主線程會(huì)自動(dòng)調(diào)用Looper.prepareMainLooper和Looper.loop,具體是在ActivityThread中main方法中調(diào)用的。
public static void main(String[] args) {
......省略無關(guān)代碼
// 主線程的Looper相關(guān)準(zhǔn)備工作
Looper.prepareMainLooper();
// Find the value for {@link #PROC_START_SEQ_IDENT} if provided on the command line.
// 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);
// 開啟消息循環(huán)
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
子線程使用Handler時(shí),首先需要調(diào)用Looper.prepare,prepare方法中,new一個(gè)Looper對(duì)象,存入ThreadLocal;在Looper的構(gòu)造中,會(huì)new一個(gè)MessageQueue,綁定到當(dāng)前Looper中。
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
// new一個(gè)Looper對(duì)象
sThreadLocal.set(new Looper(quitAllowed));
}
private Looper(boolean quitAllowed) {
// new一個(gè)MessageQueue,綁定到Looper中
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
創(chuàng)建Handler實(shí)例,在Handler構(gòu)造中,若傳入Looper,則將傳入的Looper綁定給Handler的Looper,并將傳入Looper的MessageQueue也綁定給Handler的MessageQueue。若不傳入Looper,則構(gòu)造中,直接取當(dāng)前線程的Looper以及該Looper的MessageQueue和handler綁定。
// 創(chuàng)建Handler選擇無參構(gòu)造,會(huì)走到這里
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());
}
}
// 拿到當(dāng)前線程的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()");
}
// 拿到當(dāng)前線程Looper的MessageQueue,綁定到Handler中
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
// 創(chuàng)建Handler選擇有參構(gòu)造,會(huì)走到這里
public Handler(Looper looper, Callback callback, boolean async) {
// 將傳入的Looper以及該Looper的MessageQueue綁定到Handler中,讓Handler在Looper所在的線程環(huán)境中
mLooper = looper;
mQueue = looper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
接著調(diào)用Looper.loop,拿到myLooper,也就是從ThreadLocal中取,在拿到myLooper的MessageQueue,對(duì)MessageQueue死循環(huán),MessageQueue.next()獲取消息,沒有消息則掛載。有消息時(shí),會(huì)調(diào)用message的target的dispatchMessage方法分發(fā)消息。dispatchMessage方法中,首先判斷message是否有回調(diào),有則直接將新消息傳遞給回調(diào)接口的run方法中。若message沒有回調(diào),則再判斷handler是否有回調(diào),有回調(diào),則將新消息傳遞給回調(diào)接口的handleMessage方法中。若handler也沒有回調(diào),則將消息傳遞給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;
......省略無關(guān)代碼
// 對(duì)MessageQueue死循環(huán)
for (;;) {
// MessageQueue.next()獲取消息
Message msg = queue.next(); // might block
// 沒有消息則掛載
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
......省略無關(guān)代碼
try {
// 有消息時(shí),調(diào)用message的target的dispatchMessage方法分發(fā)消息
msg.target.dispatchMessage(msg);
dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
......省略無關(guān)代碼
msg.recycleUnchecked();
}
}
// Handler分發(fā)消息
public void dispatchMessage(Message msg) {
// Message有回調(diào),則直接將新消息傳遞給回調(diào)接口的run方法中
if (msg.callback != null) {
handleCallback(msg);
} else {
// Handler有回調(diào),則將新消息傳遞給回調(diào)接口的handleMessage方法中
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
// 將消息傳遞給handler的handleMessage公開方法中
handleMessage(msg);
}
}
hander.sendMessage,會(huì)調(diào)用enqueueMessage方法,將當(dāng)前handler賦值給Message的target,然后調(diào)用handler的MessageQueue的enqueueMessage方法,內(nèi)部會(huì)將新的message添加進(jìn)MessageQueue中。此時(shí),Looper中MessageQueue會(huì)被喚醒,循環(huán)獲取到新消息做下一步處理。
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
// 將當(dāng)前handler賦值給Message的target
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
// 調(diào)用MessageQueue的enqueueMessage方法,內(nèi)部會(huì)將新的message添加進(jìn)MessageQueue鏈表中
return queue.enqueueMessage(msg, uptimeMillis);
}
相關(guān)概念
一個(gè)線程對(duì)應(yīng)一個(gè)Looper,一個(gè)Looper對(duì)應(yīng)一個(gè)MessageQueue,一個(gè)Looper可對(duì)應(yīng)多個(gè)Handler,一個(gè)Handler對(duì)應(yīng)一個(gè)Looper。
主線程中,MessageQueue死循環(huán),并不會(huì)卡死UI。在ActivityThread的main方法中,首先調(diào)用Looper.prepareMainLooper,緊接著就會(huì)new一個(gè)ActivityThread,并且拿到該主線程的mainThreadHandler,再調(diào)用Looper的loop開啟消息循環(huán)。以后UI線程的UI刷新等操作也是在mainThreadHandler發(fā)消息執(zhí)行的。
最后編輯于 :2019.04.01 09:04:51
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者 【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。 平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。