前言
本系列文章,將分享與Handler相關(guān)的知識(shí)我擂,包括Handler的結(jié)構(gòu)衬以,運(yùn)作流程,各個(gè)類的作用校摩、之間的關(guān)系
內(nèi)容提要
本篇文章將分析MessageQueue的作用看峻,以及主要的方法
重要屬性
//native層消息隊(duì)列的指針地址
private long mPtr;
// 是否允許退出消息隊(duì)列
private final boolean mQuitAllowed;
// 消息隊(duì)列尾部指針,無(wú)論做什么操作衙吩,最后都會(huì)將它指向尾部節(jié)點(diǎn)
Message mMessages;
內(nèi)部類/接口
/**
* Callback interface for discovering when a thread is going to block waiting for more messages.
*/
public static interface IdleHandler {
/**
* Called when the message queue has run out of messages and will now wait for more.
* Return true to keep your idle handler active, false to have it removed.
* This may be called if there are still messages pending in the queue, but they are all scheduled to be dispatched after the current time.
*/
boolean queueIdle();
}
native方法
private native static void nativeDestroy(long ptr);
銷(xiāo)毀消息
private native static boolean nativeIsPolling(long ptr);
消息隊(duì)列是否正在進(jìn)行輪詢
重要方法
boolean enqueueMessage(Message msg, long when)
消息入列
- 1.下面的代碼互妓,除了說(shuō)明了消息的入列規(guī)則(請(qǐng)看注釋),還表明了消息隊(duì)列的結(jié)構(gòu)坤塞,消息隊(duì)列的排布規(guī)則是由隊(duì)列頭到隊(duì)列尾冯勉,消息發(fā)送的優(yōu)先程度依次遞減,優(yōu)先從隊(duì)列尾部取消息(題外話:這樣其實(shí)與隊(duì)列(Queue)的定義不符摹芙,隊(duì)列要求只從尾部加入灼狰,頭部刪除,所以我覺(jué)得消息隊(duì)列的“隊(duì)列”瘫辩,更多屬于象征意義上的伏嗜,實(shí)際上,它是一個(gè)單向鏈表)
boolean enqueueMessage(Message msg, long when) {
if (msg.target == null) {
throw new IllegalArgumentException("Message must have a target.");
}
if (msg.isInUse()) {
throw new IllegalStateException(msg + " This message is already in use.");
}
synchronized (this) {
if (mQuitting) {
IllegalStateException e = new IllegalStateException(
msg.target + " sending message to a Handler on a dead thread");
Log.w(TAG, e.getMessage(), e);
msg.recycle();
return false;
}
msg.markInUse();
msg.when = when;
Message p = mMessages;
//是否需要喚醒native隊(duì)列
boolean needWake;
if (p == null || when == 0 || when < p.when) {
// 如果
// 1.當(dāng)前message指針為空(message指針總是指向隊(duì)尾伐厌,說(shuō)明消息隊(duì)列為空)
// 2.when==0(說(shuō)明這是一個(gè)想立即發(fā)送的message)
// 3.when < p.when(即這個(gè)消息要比message指針指向的消息更早地被發(fā)送)
// 則把傳入的message放入隊(duì)尾
// New head, wake up the event queue if blocked.
msg.next = p;
mMessages = msg;
// 在next()方法里面承绸,mBlocked可能被設(shè)為true,也就是隊(duì)列阻塞了
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.
// 在Handler分析里說(shuō)過(guò)挣轨,
// 1.正經(jīng)通過(guò)Handler發(fā)送的Message军熏,必然有target
// 2.API<28 的情況下,理論上Message必然是同步的
// 所以在一般情境下卷扮,這里needWake的值就取決于mBlocked
// 在next()方法里面荡澎,mBlocked可能被設(shè)為true,也就是隊(duì)列阻塞了
needWake = mBlocked && p.target == null && msg.isAsynchronous();
Message prev;
for (; ; ) {
prev = p;
p = p.next;
// p == null表示已經(jīng)到隊(duì)列的頭了
// when < p.when 表示p對(duì)應(yīng)的消息的到期時(shí)間已經(jīng)晚于要入列的msg了
// 任一情況晤锹,都將要入列的msg插入
if (p == null || when < p.when) {
break;
}
//只要在插入的節(jié)點(diǎn)至隊(duì)列尾部的任一節(jié)點(diǎn)是異步的摩幔,都不需要喚醒native隊(duì)列(其實(shí)我也沒(méi)搞懂是啥意思)
if (needWake && p.isAsynchronous()) {
needWake = false;
}
}
msg.next = p; // invariant: p == prev.next
prev.next = msg;
}
// We can assume mPtr != 0 because mQuitting is false.
// 當(dāng)隊(duì)列被阻塞鞭铆,喚醒隊(duì)列
if (needWake) {
nativeWake(mPtr);
}
}
return true;
}
Message next()
取出下一條到期的Message
Message next() {
// Return here if the message loop has already quit and been disposed.
// This can happen if the application tries to restart a looper after quit which is not supported.
// native消息隊(duì)列的指針
final long ptr = mPtr;
// ptr == 0 或衡,說(shuō)明沒(méi)有消息了
// 這里是否說(shuō)明,入列的消息其實(shí)會(huì)被存放到native層(至少是存一個(gè)副本)?
// 但是并沒(méi)有觀察到有相關(guān)的代碼
if (ptr == 0) {
return null;
}
int pendingIdleHandlerCount = -1; // -1 only during first iteration
//下一次輪詢的時(shí)間間隔
int nextPollTimeoutMillis = 0;
for (; ; ) {
if (nextPollTimeoutMillis != 0) {
// Binder通信機(jī)制封断,知識(shí)盲區(qū)斯辰,研究了再補(bǔ)
Binder.flushPendingCommands();
}
//執(zhí)行一次輪詢,取出待發(fā)送的消息坡疼,如果沒(méi)有可用的消息彬呻,這里會(huì)阻塞,直到被重新喚醒
nativePollOnce(ptr, nextPollTimeoutMillis);
synchronized (this) {
// Try to retrieve the next message. Return if found.
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;
// 一般情境下柄瑰,不存在沒(méi)有target的msg闸氮,所以這部分大概率不走
if (msg != null && msg.target == null) {
//msg不為空,但是該msg不持有Handler
// Stalled by a barrier. Find the next asynchronous message in the queue.
do {
prevMsg = msg;
msg = msg.next;
//如果msg不為空且不是異步的狱意,取下一個(gè)
//也就是說(shuō)需要找出來(lái)一個(gè)異步msg湖苞,或者到隊(duì)列最后
} while (msg != null && !msg.isAsynchronous());
}
if (msg != null) {
// 1.正常的msg
// 2.最終找到一個(gè)異步的msg
if (now < msg.when) {
// 如果當(dāng)前msg還沒(méi)到發(fā)送時(shí)間,把時(shí)間差記下來(lái)详囤,下一次輪詢會(huì)按照這個(gè)時(shí)間差等待
// 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;
//取出msg
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 {
// 暫時(shí)沒(méi)消息了财骨,下一次輪詢將會(huì)阻塞
// No more messages.
nextPollTimeoutMillis = -1;
}
// Process the quit message now that all pending messages have been handled.
// 如果正在退出隊(duì)列,就銷(xiāo)毀消息
if (mQuitting) {
dispose();
return null;
}
// If first time idle, then get the number of idlers to run.
// Idle handles only run if the queue is empty or if the first message in the queue (possibly a barrier) is due to be handled in the future.
// 這下面的代碼是我不能理解的藏姐,貌似這部分是在異步消息的情況下才有作用的
if (pendingIdleHandlerCount < 0
&& (mMessages == null || now < mMessages.when)) {
pendingIdleHandlerCount = mIdleHandlers.size();
}
if (pendingIdleHandlerCount <= 0) {
// No idle handlers to run. Loop and wait some more.
mBlocked = true;
continue;
}
if (mPendingIdleHandlers == null) {
mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
}
mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
}
// Run the idle handlers.
// We only ever reach this code block during the first iteration.
for (int i = 0; i < pendingIdleHandlerCount; i++) {
final IdleHandler idler = mPendingIdleHandlers[i];
mPendingIdleHandlers[i] = null; // release the reference to the handler
boolean keep = false;
try {
keep = idler.queueIdle();
} catch (Throwable t) {
Log.wtf(TAG, "IdleHandler threw exception", t);
}
if (!keep) {
synchronized (this) {
mIdleHandlers.remove(idler);
}
}
}
// Reset the idle handler count to 0 so we do not run them again.
pendingIdleHandlerCount = 0;
// While calling an idle handler, a new message could have been delivered
// so go back and look again for a pending message without waiting.
nextPollTimeoutMillis = 0;
}
}
void quit(boolean safe)
退出消息隊(duì)列
- 1.這里會(huì)判斷是否允許退出(主線程的消息隊(duì)列就是不允許退出的)和是否已經(jīng)在執(zhí)行退出了
- 2.根據(jù)是否安全退出隆箩,會(huì)移除所有未被發(fā)送的Message/移除所有Message
- 3.最后調(diào)用了一個(gè)native方法nativeWake(),看資料說(shuō)是喚醒底層的隊(duì)列羔杨,目前還沒(méi)看native層的源碼捌臊,下回分解
void quit(boolean safe) {
if (!mQuitAllowed) {
throw new IllegalStateException("Main thread not allowed to quit.");
}
synchronized (this) {
if (mQuitting) {
return;
}
mQuitting = true;
if (safe) {
removeAllFutureMessagesLocked();
} else {
removeAllMessagesLocked();
}
// We can assume mPtr != 0 because mQuitting was previously false.
nativeWake(mPtr);
}
}
private void removeAllFutureMessagesLocked()
移除所有未到期的message
- 1.如果隊(duì)列尾部的指針已經(jīng)是未到期(p.when > now),那么按照消息隊(duì)列的排隊(duì)規(guī)則兜材,后面的消息肯定都沒(méi)有到期理澎,直接removeAllMessagesLocked()全部移除
- 2.找出到期的第一個(gè)msg,后面全部移除
private void removeAllFutureMessagesLocked() {
final long now = SystemClock.uptimeMillis();
Message p = mMessages;
if (p != null) {
if (p.when > now) {
removeAllMessagesLocked();
} else {
Message n;
for (; ; ) {
n = p.next;
if (n == null) {
return;
}
if (n.when > now) {
break;
}
p = n;
}
p.next = null;
do {
p = n;
n = p.next;
p.recycleUnchecked();
} while (n != null);
}
}
}
private void removeAllMessagesLocked()
很簡(jiǎn)單曙寡,全部消息移除
private void removeAllMessagesLocked() {
Message p = mMessages;
while (p != null) {
Message n = p.next;
p.recycleUnchecked();
p = n;
}
mMessages = null;
}
private void dispose()
- 1.處理native層的消息隊(duì)列
- 2.這個(gè)方法必須在looper線程或者在finalizer方法里面調(diào)用
- 3.mPtr是native層消息隊(duì)列的指針糠爬,通過(guò)調(diào)用native方法nativeDestroy(mPtr),銷(xiāo)毀消息
private void dispose() {
if (mPtr != 0) {
nativeDestroy(mPtr);
mPtr = 0;
}
}
本篇內(nèi)容到此結(jié)束举庶,感謝收看~~