核心成員
- Handler
提供各種api調(diào)用,例如接收消息左腔、發(fā)送消息耀找、創(chuàng)建一個Message等
- Message
消息實體野芒,承載數(shù)據(jù)
- MessageQueue
消息隊列
- Looper
循環(huán)機(jī)制
Handler的創(chuàng)建
public Handler(@NonNull Looper looper, @Nullable Callback callback, boolean async) {
mLooper = looper;
mQueue = looper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
- looper
循環(huán)機(jī)制,如果是在主線程中收發(fā)消息可以直接將Looper.getMainLooper()作為入?yún)⒋樽ァandler中的消息隊列其實用的就會looper里的消息隊列
- callback
public interface Callback {
/**
* @param msg A {@link android.os.Message Message} object
* @return True if no further handling is desired
*/
boolean handleMessage(@NonNull Message msg);
}
在handler中有這樣一個接口丹拯,里面就一個方法handleMessage,返回boolean乖酬,在消息分發(fā)的過程中會先將Message傳遞給這個callback咬像,返回true的時候,handler本身的handleMessage方法就不會接收到這個Message了
public void dispatchMessage(@NonNull Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
從源碼中可以看到Message也有一個callback肮柜,但這個callback是一個Runable审洞,比如我們通過handler.post的方法發(fā)起消息時待讳,就是將這個消息作為一個callback去處理
- async
暫無
sendMessage(發(fā)送消息)
發(fā)送消息相關(guān)的的api有很多個:
- sendMessage
- sendEmptyMessage
- sendEmptyMessageDelayed
- sendEmptyMessageAtTime
- sendMessageDelayed
- post
- postDelay
他們最終調(diào)用的都是sendMessageAtTime
public final boolean sendMessageDelayed(@NonNull Message msg, long delayMillis) {
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
public boolean sendMessageAtTime(@NonNull Message msg, long uptimeMillis) {
MessageQueue queue = mQueue;
if (queue == null) {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
return false;
}
return enqueueMessage(queue, msg, uptimeMillis);
}
private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,
long uptimeMillis) {
msg.target = this;
msg.workSourceUid = ThreadLocalWorkSource.getUid();
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
從源碼中可以發(fā)現(xiàn)撰糠,延時消息其實就是當(dāng)前系統(tǒng)時間+延時時間辩昆,這里我們差不多也能猜到,延時消息的原理基本就是根據(jù)時間將消息進(jìn)行排序术辐,在固定的時間點進(jìn)行發(fā)送施无,但是我們發(fā)現(xiàn)Handler僅僅只是調(diào)用了隊列的enqueueMessage方法猾骡,那么這些排序操作也就是隊列去完成的了,另外在enqueueMessage中還進(jìn)行了target的賦值幢哨,就是把Handler自己傳進(jìn)去嫂便,這一步就為了當(dāng)Looper在處理消息的時候調(diào)用Handler的dispatchMessage方法進(jìn)行消息分發(fā)
Looper
Looper.loop會啟動一個死循環(huán),主線程在啟動的時候就已經(jīng)做了這些事情
public static void loop() {
//......
for (;;) {
if (!loopOnce(me, ident, thresholdOverride)) {
return;
}
}
}
private static boolean loopOnce(final Looper me,
final long ident, final int thresholdOverride){
Message msg = me.mQueue.next(); // might block
//...
try {
msg.target.dispatchMessage(msg);
if (observer != null) {
observer.messageDispatched(token, msg);
}
dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
} catch (Exception exception) {
if (observer != null) {
observer.dispatchingThrewException(token, msg, exception);
}
throw exception;
} finally {
ThreadLocalWorkSource.restore(origWorkSource);
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
//...
}
在這死循環(huán)中會不斷的調(diào)用loopOnce方法践樱,loopOnce中其實也是通過調(diào)用隊列的next()方法直接拿出消息然后調(diào)用dispatchMessage進(jìn)行事件分發(fā)拷邢,那么延時消息到底是怎么做到定時發(fā)送的呢甲雅?這個答案就在mQueue.next()中
MessageQueue
通過以上的分析,整個消息收發(fā)流程中比較重要的是消息隊列,消息排序脐瑰,處理延時消息,獲取消息這些邏輯都在這里面
MessageQueue.enqueueMessage()
boolean enqueueMessage(Message msg, long when){
//.....
msg.markInUse();
msg.when = when;
Message p = mMessages;
boolean needWake;
if (p == null || when == 0 || when < p.when) {
// New head, wake up the event queue if blocked.
msg.next = p;
mMessages = msg;
needWake = mBlocked;
} else {
// Inserted within the middle of the queue. Usually we don't have to wake
// up the event queue unless there is a barrier at the head of the queue
// and the message is the earliest asynchronous message in the queue.
needWake = mBlocked && p.target == null && msg.isAsynchronous();
Message prev;
for (;;) {
prev = p;
p = p.next;
if (p == null || when < p.when) {
break;
}
if (needWake && p.isAsynchronous()) {
needWake = false;
}
}
msg.next = p; // invariant: p == prev.next
prev.next = msg;
}
//....
}
enqueueMessage主要負(fù)責(zé)消息的插入,msg.when就是這個消息應(yīng)該觸發(fā)的時間寂恬,也就是當(dāng)前系統(tǒng)時間+延時時間,整個隊列是以時間為準(zhǔn)從小到大排列酷鸦。在這個方法中你會發(fā)現(xiàn)這樣一段代碼
// We can assume mPtr != 0 because mQuitting is false.
if (needWake) {
nativeWake(mPtr);
}
這個與MessageQueue.next()中的nativePollOnce(ptr, nextPollTimeoutMillis)相對應(yīng)臼隔,ptr指向的是native code妄壶,通過native方法nativeInit()獲取。nativePollOnce讓程序進(jìn)入等待狀態(tài)氨淌,nativeWake則會喚醒伊磺,就像Thread.wait()和Thread.notify(),但兩者在底層機(jī)制上是有區(qū)別的蛮艰,nativePollOnce底層是運用了epoll機(jī)制,Thread.wait()是Futex即寡,這么做也是為了不浪費CPU資源袜刷。
MessageQueue.next()中的
Message next() {
//...
int nextPollTimeoutMillis = 0;
for (;;) {
//...
nativePollOnce(ptr, nextPollTimeoutMillis);
//...
if (msg != null) {
if (now < msg.when) {
// Next message is not ready. Set a timeout to wake up when it is ready.
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
} else {
// Got a message.
mBlocked = false;
if (prevMsg != null) {
prevMsg.next = msg.next;
} else {
mMessages = msg.next;
}
msg.next = null;
if (DEBUG) Log.v(TAG, "Returning message: " + msg);
msg.markInUse();
return msg;
}
} else {
// No more messages.
nextPollTimeoutMillis = -1;
}
}
//...
}
這里面也有一個for循環(huán)著蟹,這個循環(huán)會一直等到有消息可以處理才會停止。對于延時消息奸披,會記錄延時的時間nextPollTimeoutMillis涮雷,然后在下次循環(huán)的時候會調(diào)用nativePollOnce進(jìn)入等待。
IdleHandler
在MessageQueue.next()中样刷,除了以上的工作外置鼻,還會處理IdleHandler消息蜓竹。如果當(dāng)前沒有需要處理的消息,處于空閑階段時會處理掉所有的IdleHandler消息司蔬。
用法:
Looper.getMainLooper().queue.addIdleHandler(object : MessageQueue.IdleHandler {
override fun queueIdle(): Boolean {
TODO("Not yet implemented")
}
})