前言
阅读本文的前提是了解一些基类,如Handler、Looper和ThreadLocal。 可以在这里搜索源代码的位置。
源代码分析
分析枚举消息方法
布尔型消息(消息msg,long when ) {
if (msg.target==空值) {
thrownewillegalargumentexception (' messagemusthaveatarget.' );
}
if(msg.isinuse () ) )。
thrownewillegalstateexception (msg ' thismessageisalreadyinuse.';
}
同步(this ) {
if(mquitting ) {
illegalstateexceptione=newillegalstateexception (
msg.target ' sendingmessagetoahandleronadeadthread ';
log.w(tag,e.getMessage ),e );
msg.recycle (;
返回假;
}
msg.markInUse (;
msg.when=when;
Message p=mMessages;
布尔新闻工作;
if (p==空||when==0||whenp.when ) {
//New head,wake up the event queue if blocked。
msg.next=p;
mMessages=msg;
needWake=mBlocked;
} else {
//insertedwithinthemiddleofthequeue.usually we don ' thavetowake
//uptheeventqueueunlessthereisabarrierattheheadofthequeue
//andthemessageistheearliestasynchronousmessageinthequeue。
need wake=m blocked p.target==null msg.is asynchronous (;
消息预;
for (; () )。
prev=p;
p=p.next;
if (p==空||whenp.when ) {
黑;
}
if(Needwakep.isasynchronous () ) )。
needWake=false;
}
}
msg.next=p; //invariant: p==prev.next
prev.next=msg;
}
//We can assume mPtr!=0 because mQuitting is false。
if(needwake ) {
导航(mptr );
}
}
返回真;
}
作为消息队列的内部组织,消息的数据结构实际上是一个链表,按消息when字段的升序排列。 主要看如何将消息链接到链表。
消息分为同步消息和异步消息两种。 一个可以用方法isAsynchronous判断。 如果消息链表开头是障碍,则无法处理该障碍后面的同步消息,但异步消息不受影响。
我们正常使用的时候大部分情况下都是同步消息。 但是,添加屏障的接口是专用API。 这意味着,只要不反射,开发者就无法调用这个API。
现在开始分析代码。 比较重要的代码是以下行
msg.when=when;
Message p=mMessages;
布尔新闻工作;
if (p==空||when==0||whenp.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;
}
// We can assume mPtr != 0 because mQuitting is false.
if (needWake) {
nativeWake(mPtr);
}
如果当前链表为null或者当前消息的触发时间(when)小于链表头的触发时间,那么直接把这个消息加到链表的头部,next指向原头部,如果当前next函数是阻塞的,那么要唤醒next函数。
如果当前链表并且msg的触发时间要比链表头部msg触发时间要大,那么就遍历这个链表,找到它应该在的位置(按when升序)。
这里面有个唤醒next 方法的策略,就是这个needWake变量,如果当前头部的msg是个屏障消息,并且next函数是阻塞的,并且msg是这个链表中触发时间最早的,那么需要唤醒next函数。我们来分析下这几个条件:
如果next没阻塞,那么无论msg是什么,我们都不需要唤醒next。
如果next阻塞,但是链表头部是非屏障消息,说明头部还不到时间执行,到了时间next会自动唤醒,所以手动不需要唤醒。
如果next 阻塞,头部是屏障消息,如果msg不是触发最早的异步消息,那么说明最早的异步消也在等待处理,next函数在指定时间差内会自动唤醒,此时不需要手动唤醒。如果msg是最早的异步消息,那msg后面有可能有异步消息,也有可能没有异步消息,在有异步消息的情况,要重新唤醒next,为了及时能处理当前msg,在没有的情况下也要唤醒next,因为此时next是永久阻塞,阻塞参数为-1。
我们分析下next函数
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.
final long ptr = mPtr;
if (ptr == 0) {
return null;
}
int pendingIdleHandlerCount = -1; // -1 only during first iteration
int nextPollTimeoutMillis = 0;
for (;;) {
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();
}
//阻塞函数
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;//链表的头部
if (msg != null && msg.target == null) {//如果头消息是个屏障消息
// Stalled by a barrier. Find the next asynchronous message in the queue.
do {//那么循环找异步消息来处理
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
if (msg != null) {
if (now < msg.when) {//如果还不到时间执行,那么next会阻塞一个指定时间段
// 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 {//直接返回给Looper
// 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 {//如果没找到消息,那么next可能会陷入阻塞
// No more messages.
nextPollTimeoutMillis = -1;
}
// Process the quit message now that all pending messages have been handled.
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) {//如果没空闲任务做,那么next就会陷入阻塞,nextPollTimeoutMillis=-1的话,就永远阻塞。
// 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;
}
}
把关键解析写在注释里了。核心的意思,如果头部是空或者头部是屏障消息并且后面没有异步消息,那么next陷入永久阻塞,否则的话,直接处理头部消息,如果头部消息还不到时间处理,那么next会被阻塞(when-now)这么久,否则的话,直接返回给Looper