概述
消息機(jī)制涉及MessageQueue/Message/Looper/Handler這4個(gè)類。
說(shuō)明
- Message:消息分為硬件產(chǎn)生的消息(如按鈕、觸摸)和軟件生成的消息;,Message有自己的緩存池,避免message的頻繁創(chuàng)建銷毀
- MessageQueue:消息隊(duì)列的主要功能向消息池投遞消息(MessageQueue.enqueueMessage)和取走消息池的消息(MessageQueue.next);
- Handler:消息輔助類,主要功能向消息池發(fā)送各種消息事件(Handler.sendMessage)和處理相應(yīng)消息事件(Handler.handleMessage);
- Looper:不斷循環(huán)執(zhí)行(Looper.loop),按分發(fā)機(jī)制將消息分發(fā)給目標(biāo)處理者。
類關(guān)系
- Looper有一個(gè)MessageQueue消息隊(duì)列;
- MessageQueue有一組待處理的Message;
- Message中有一個(gè)用于處理消息的Handler;
- Handler中有Looper和MessageQueue;
ThreadLocal
- 線程本地存儲(chǔ)區(qū)(Thread Local Storage,簡(jiǎn)稱為TLS),每個(gè)線程都有自己的私有的本地存儲(chǔ)區(qū)域,不同線程之間彼此不能訪問對(duì)方的TLS區(qū)域。
- 每個(gè)線程可以有多個(gè)TLS,一個(gè)TLS對(duì)應(yīng)一個(gè)value
- Looper 創(chuàng)建就以TLS方式創(chuàng)建,一個(gè)線程中最多只能有1個(gè)Looper
主線程驅(qū)動(dòng)
- 主線程最終就是調(diào)用Looper的loop方法進(jìn)入死循環(huán),進(jìn)行消息驅(qū)動(dòng)
- 主線程的Looper 是在 ActivityThread main函數(shù)中創(chuàng)建的
public static void main(String[] args) {
// Install selective syscall interception
AndroidOs.install();
// CloseGuard defaults to true and can be quite spammy. We
// disable it here, but selectively enable it later (via
// StrictMode) on debug builds, but using DropBox, not logs.
CloseGuard.setEnabled(false);
Environment.initForCurrentUser();
// Make sure TrustedCertificateStore looks in the right place for CA certificates
final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
TrustedCertificateStore.setDefaultUserDirectory(configDir);
Process.setArgV0("<pre-initialized>");
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);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
- 消息生產(chǎn)
- handler::enqueueMessage,MessageQueue是按照Message觸發(fā)時(shí)間的先后順序排列的,隊(duì)頭的消息是將要最早觸發(fā)的消息。當(dāng)有消息需要加入消息隊(duì)列時(shí),會(huì)從隊(duì)列頭開始遍歷,直到找到消息應(yīng)該插入的合適位置,以保證所有消息的時(shí)間順序。
- 消息消費(fèi)(在loop中)
- 讀取MessageQueue的下一條Message;
Message next() {
final long ptr = mPtr;
if (ptr == 0) { //當(dāng)消息循環(huán)已經(jīng)退出,則直接返回
return null;
}
int pendingIdleHandlerCount = -1; // 循環(huán)迭代的首次為-1
int nextPollTimeoutMillis = 0;
for (;;) {
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();
}
//nativePollOnce是阻塞操作,其中nextPollTimeoutMillis代表下一個(gè)消息到來(lái)前,還需要等待的時(shí)長(zhǎng);當(dāng)nextPollTimeoutMillis = -1時(shí),表示消息隊(duì)列中無(wú)消息,會(huì)一直等待下去。
nativePollOnce(ptr, nextPollTimeoutMillis);
synchronized (this) {
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;
//當(dāng)消息的Handler為空時(shí),則查詢異步消息
if (msg != null && msg.target == null) {
//當(dāng)查詢到異步消息,則立刻退出循環(huán)
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
if (msg != null) {
if (now < msg.when) {
//當(dāng)異步消息觸發(fā)時(shí)間大于當(dāng)前時(shí)間,則設(shè)置下一次輪詢的超時(shí)時(shí)長(zhǎng)
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
} else {
// 獲取一條消息,并返回
mBlocked = false;
if (prevMsg != null) {
prevMsg.next = msg.next;
} else {
mMessages = msg.next;
}
msg.next = null;
//設(shè)置消息的使用狀態(tài),即flags |= FLAG_IN_USE
msg.markInUse();
return msg; //成功地獲取MessageQueue中的下一條即將要執(zhí)行的消息
}
} else {
//沒有消息
nextPollTimeoutMillis = -1;
}
//消息正在退出,返回null
if (mQuitting) {
dispose();
return null;
}
//當(dāng)消息隊(duì)列為空,或者是消息隊(duì)列的第一個(gè)消息時(shí)
if (pendingIdleHandlerCount < 0 && (mMessages == null || now < mMessages.when)) {
pendingIdleHandlerCount = mIdleHandlers.size();
}
if (pendingIdleHandlerCount <= 0) {
//沒有idle handlers 需要運(yùn)行,則循環(huán)并等待。
mBlocked = true;
continue;
}
if (mPendingIdleHandlers == null) {
mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
}
mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
}
//只有第一次循環(huán)時(shí),會(huì)運(yùn)行idle handlers,執(zhí)行完成后,重置pendingIdleHandlerCount為0.
for (int i = 0; i < pendingIdleHandlerCount; i++) {
final IdleHandler idler = mPendingIdleHandlers[i];
mPendingIdleHandlers[i] = null; //去掉handler的引用
boolean keep = false;
try {
keep = idler.queueIdle(); //idle時(shí)執(zhí)行的方法
} catch (Throwable t) {
Log.wtf(TAG, "IdleHandler threw exception", t);
}
if (!keep) {
synchronized (this) {
mIdleHandlers.remove(idler);
}
}
}
//重置idle handler個(gè)數(shù)為0,以保證不會(huì)再次重復(fù)運(yùn)行
pendingIdleHandlerCount = 0;
//當(dāng)調(diào)用一個(gè)空閑handler時(shí),一個(gè)新message能夠被分發(fā),因此無(wú)需等待可以直接查詢pending message.
nextPollTimeoutMillis = 0;
}
}
- 把Message分發(fā)給相應(yīng)的target;
- 再把分發(fā)后的Message回收到消息池,以便重復(fù)利用。
IdleHandler
每次在獲取下一個(gè)message時(shí),沒有獲取到時(shí)執(zhí)行idleHnalder的runable
整體流程

handler_java.jpg
- Handler通過(guò)sendMessage()發(fā)送Message到MessageQueue隊(duì)列;
- Looper通過(guò)loop(),不斷提取出達(dá)到觸發(fā)條件的Message,并將Message交給target來(lái)處理;
- 經(jīng)過(guò)dispatchMessage()后,交回給Handler的handleMessage()來(lái)進(jìn)行相應(yīng)地處理。
- 將Message加入MessageQueue時(shí),處往管道寫入字符,可以會(huì)喚醒loop線程;如果MessageQueue中沒有Message,并處于Idle狀態(tài),則會(huì)執(zhí)行IdelHandler接口中的方法,往往用于做一些清理性地工作。
Native 層 消息機(jī)制
在整個(gè)消息機(jī)制中,而MessageQueue是連接Java層和Native層的紐帶,換言之,Java層可以向MessageQueue消息隊(duì)列中添加消息,Native層也可以向MessageQueue消息隊(duì)列中添加消息,接下來(lái)來(lái)看看MessageQueue。

handler_arch.png
- 紅色虛線關(guān)系:Java層和Native層的MessageQueue通過(guò)JNI建立關(guān)聯(lián),彼此之間能相互調(diào)用,搞明白這個(gè)互調(diào)關(guān)系,也就搞明白了Java如何調(diào)用C++代碼,C++代碼又是如何調(diào)用Java代碼。
- 藍(lán)色虛線關(guān)系:Handler/Looper/Message這三大類Java層與Native層并沒有任何的真正關(guān)聯(lián),只是分別在Java層和Native層的handler消息模型中具有相似的功能。都是彼此獨(dú)立的,各自實(shí)現(xiàn)相應(yīng)的邏輯。
- WeakMessageHandler繼承于MessageHandler類,NativeMessageQueue繼承于MessageQueue類
MessageQueue通過(guò)mPtr變量保存NativeMessageQueue對(duì)象,從而使得MessageQueue成為Java層和Native層的樞紐,既能處理上層消息,也能處理native層消息;下面列舉Java層與Native層的對(duì)應(yīng)圖
另外,消息處理流程是先處理Native Message,再處理Native Request,最后處理Java Message。理解了該流程,也就明白有時(shí)上層消息很少,但響應(yīng)時(shí)間卻較長(zhǎng)的真正原因。
- Native Message:和java層類似,由native的
- Native Request: 由fd觸發(fā)的event,這些文件描述符可以讓其他組件注冊(cè),發(fā)送
refrence
http://www.itdecent.cn/p/f7cabfe19720
Android Handler 通信 - 徹底了解 Handler 的通信過(guò)程