- 《Android Handler机制》
- 《Android Handler分析(一) Handler和Message详解》
- 《Android Handler分析 (二) MessageQueue详解》
- 《Android Handler分析 (三) Looper详解和Handler其他知识》
- 《Android 中的 HandlerThread 类详解》
在上一篇博客《Android Handler分析(一) Handler和Message详解》中我们说到了Android中Handler机制的两个重要类Message和Handler,在这篇博客中,我们继续来看一下另外的一个重要类,MessageQueue(消息队列)类。
MessageQueue源码分析:
1. MessageQueue中的一些成员变量
private final boolean mQuitAllowed; // MessageQueue是否可以退出,如果是主线程的就不能退出
private long mPtr; // used by native code,native方法中使用的,表示native代码中的MessageQueue地址
Message mMessages; // Message是一个链表结构,mMessages表示链表的第一个元素,也就是消息队列的队首
private final ArrayList<IdleHandler> mIdleHandlers = new ArrayList<IdleHandler>();// 用来保存IdleHandler对象的集合
private IdleHandler[] mPendingIdleHandlers;// 用来保存IdleHandler对象的数组,在后面会将集合中的对象复制到数组中
private boolean mQuitting; // 当前消息队列是否处于退出状态
private boolean mBlocked; // 表示在next()方法中是否被阻塞在超时时间非0的native pollOnce()方法上。
private int mNextBarrierToken; // 表示下一个Barrier(障碍物,屏障;界线)的标记(令牌)
2. 看一下IdleHandler接口
/**
* 这个接口是当next()方法没有获取到或者在等待可以执行的消息时,就可以执行这个接口的回调
*/
public static interface IdleHandler {
/**
* 回调方法,返回boolean类型的值,如果返回true表示不移除,返回false表示执行完之后就从集合中移除该对象
*/
boolean queueIdle();
}
// 增加一个IdleHandler接口实现类对象到mIdleHandlers集合中
public void addIdleHandler(@NonNull IdleHandler handler) {
if (handler == null) {
throw new NullPointerException("Can't add a null IdleHandler");
}
synchronized (this) {
mIdleHandlers.add(handler);
}
}
// 从mIdleHandlers集合中移除这个IdleHandler对象
public void removeIdleHandler(@NonNull IdleHandler handler) {
synchronized (this) {
mIdleHandlers.remove(handler);
}
}
下面是系统ActivityThread.java中的一个使用IdleHandler的例子
final GcIdler mGcIdler = new GcIdler();
// 创建内部类实现 IdleHandler 接口
final class GcIdler implements MessageQueue.IdleHandler {
@Override
public final boolean queueIdle() {
// 调用关于gc的方法,即当Handler没有消息可以执行时调用一下doGcIfNeeded()方法进行垃圾回收
doGcIfNeeded();
// 返回false,表示执行完之后就移除
return false;
}
}
void scheduleGcIdler() {
if (!mGcIdlerScheduled) {
mGcIdlerScheduled = true;
// 调用MessageQueue的addIdleHandler()方法将mGcIdler添加到集合
Looper.myQueue().addIdleHandler(mGcIdler);
}
mH.removeMessages(H.GC_WHEN_IDLE);
}
void unscheduleGcIdler() {
if (mGcIdlerScheduled) {
mGcIdlerScheduled = false;
// 从集合中移除mGcIdler对象
Looper.myQueue().removeIdleHandler(mGcIdler);
}
mH.removeMessages(H.GC_WHEN_IDLE);
}
在ActivityThread.java类中还有一些使用了这个接口,大家有兴趣可以去查看一下
3. MessageQueue对象的创建
// 构造方法,默认修饰符,开发者不能创建,是在创建Looper时系统创建的,并和Looper绑定在一起
// 参数quitAllowed 表示该消息队列是否可以退出,主线程的不可以退出,其他线程的可以退出
MessageQueue(boolean quitAllowed) {
mQuitAllowed = quitAllowed;
mPtr = nativeInit();
}
4. 判断消息队列中是否有指定消息
boolean hasMessages(Handler h, int what, Object object) {
// 如果Handler为null,直接返回false
if (h == null) {
return false;
}
// 同步操作
synchronized (this) {
Message p = mMessages;
// 遍历消息队列,获取每一个消息
while (p != null) {
// 将获取到的消息与参数进行比较
if (p.target == h && p.what == what && (object == null || p.obj == object)) {
// 找到了,返回true
return true;
}
// 链表,移动到下一个
p = p.next;
}
// 没有找到,返回false
return false;
}
}
// 判断方式一样,源码就不贴出来了
boolean hasMessages(Handler h, Runnable r, Object object) {}
5. MessageQueue中的enqueueMessage()方法(非常重要)
在上一篇博客《Android Handler分析(一) Handler和Message详解》中,我们使用Handler发送一个消息,我们就看到了Handler中并没有很多操作,最终都是调用MessageQueue中的enqueueMessage()方法并将Message对象作为参数传递过来。上一篇博客中我们并没有说到这个过程,现在,我们就一起来看看这个方法的庐山正面目吧。
boolean enqueueMessage(Message msg, long when) {
// target表示Handler对象,在上一篇博客中已经强调过了。
// 如果消息没有绑定Handler对象,直接抛出一个异常
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);
// 已经退出,释放消息,返回false。消息加入队列失败
msg.recycle();
return false;
}
// 指定消息正在使用
msg.markInUse();
// Message的when设置为参数的when
msg.when = when;
// 定义一个临时变量保存队列的头(队首的消息)
Message p = mMessages;
boolean needWake;
if (p == null || when == 0 || when < p.when) {
// 如果队列为null或者when为0或者when<p.when,那么这个消息就作为队列的头,并和原来的队列连接起来
msg.next = p;
mMessages = msg;
needWake = mBlocked;
} else {
// 如果队列不为空,就将消息摆放到队列中合适的位置
needWake = mBlocked && p.target == null && msg.isAsynchronous();
Message prev;
// 遍历队列,按时间顺序将消息排列
for (;;) {
prev = p;
p = p.next;
if (p == null || when < p.when) {
// 当满足 p = null (到了最后一个)或者 when < p.when 时(根据执行时间找到合适了位置了)跳出循环
break;
}
if (needWake && p.isAsynchronous()) {
needWake = false;
}
}
// 将Message插入到队列中
msg.next = p; // invariant: p == prev.next
prev.next = msg;
}
// We can assume mPtr != 0 because mQuitting is false.
// 如果需要唤醒,调用native方法,让轮询器继续取消息
if (needWake) {
nativeWake(mPtr);
}
}
// 返回true,Message加入队列成功
return true;
}
在我们调用Handler中的发送消息方法时,Handler会调用MessageQueue中的enqueueMessage()方法来将消息加入到消息队列中,然后让轮询器获取消息。MessageQueue是一个链表,如果对链表不了解的,可以查看《数据结构——链表(一)》和《数据结构——链表(二)》。
下面我们就来看一下MessageQueue中另一个非常重要的方法,next()
方法,它返回下一个需要处理的Message,在 Looper.loop()
中方法调用
6. MessageQueue中的next()方法(非常重要)
next()
方法的主要作用就是从消息队列中取出下一个需要执行的方法
Message next() {
// 定义变量保存native代码中的消息队列地址值
final long ptr = mPtr;
// 如果地址值为0,表示队列不存在,返回null
if (ptr == 0) {
return null;
}
// 保存IdleHandler对象的集合的大小,初始化时设置为 -1
int pendingIdleHandlerCount = -1; // -1 only during first iteration
// 执行下一个消息需要等待的时间
int nextPollTimeoutMillis = 0;
for (;;) {
if (nextPollTimeoutMillis != 0) {
// 如果nextPollTimeoutMillis != 0的话,调用Binder.flushPendingCommands()
Binder.flushPendingCommands();
}
// 进入native层,有可能会阻塞next()方法执行,
// 等待nextPollTimeoutMillis的时间后开始执行
nativePollOnce(ptr, nextPollTimeoutMillis);
synchronized (this) {
// 记录当前时间
final long now = SystemClock.uptimeMillis();
// 初始化变量prevMsg为null,msg为mMessges(第一个消息)
Message prevMsg = null;
Message msg = mMessages;
if (msg != null && msg.target == null) {
// msg.target == null表示此消息为消息屏障(通过MessageQueue#postSyncBarrier()方法发送来的)
// 如果发现了一个消息屏障,会循环找出第一个异步消息(如果有异步消息的话),所有同步消息都将忽略(平常发送的一般都是同步消息)
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
if (msg != null) {
// 找到了可执行的消息
if (now < msg.when) {
// 找到了,但是Message还没到执行的时间,就设置一个等待时间
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的下一个为null
msg.next = null;
if (DEBUG) Log.v(TAG, "Returning message: " + msg);
// 设置msg正在使用
msg.markInUse();
// 返回找到的Message(需要现在处理的Message)
return msg;
}
} else {
// 没有找到可执行的消息,设置 nextPollTimeoutMillis 为 -1,会一直阻塞,直到被唤醒
nextPollTimeoutMillis = -1;
}
/************** 走到这里表示没有找到可以返回的消息 ***************/
// 如果队列需要退出,调用方法销毁队列,并返回null
if (mQuitting) {
dispose();
return null;
}
/************** 开始处理IdleHandler,用于空闲的时候处理不紧急事件 ***************/
// 只有在第一次循环的时候才会走这步,因为 pendingIdleHandlerCount 的初始值是 -1
if (pendingIdleHandlerCount < 0
&& (mMessages == null || now < mMessages.when)) {
pendingIdleHandlerCount = mIdleHandlers.size();
}
if (pendingIdleHandlerCount <= 0) {
// 集合中没有IdleHandler对象(没有需要空闲时处理的逻辑),继续等待,并跳出此次循环
mBlocked = true;
continue;
}
// 没有跳出循环,表示集合中有元素,
// 如果保存IdleHandler对象的数组为null,就创建一个
if (mPendingIdleHandlers == null) {
mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
}
// 将集合中的IdleHandler对象复制到数组中
mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
}
// 遍历数组
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 {
// 执行IdleHandler的回调
keep = idler.queueIdle();
} catch (Throwable t) {
Log.wtf(TAG, "IdleHandler threw exception", t);
}
if (!keep) {
// 如果keep为false,表示该IdleHandler可以从集合中移出,那么就移除集合中的IdleHandler对象
// 否则不移除,空闲时间再次可能调用
synchronized (this) {
mIdleHandlers.remove(idler);
}
}
}
// 重置值
pendingIdleHandlerCount = 0;
nextPollTimeoutMillis = 0;
}
}
注释在代码中写得比较详细,在这里就不在啰嗦了。
7. MessageQueue中的移除方法
我们可以调用Handler中的移除消息方法,其主要逻辑也是在MessageQueue中。
void removeMessages(Handler h, int what, Object object) {
// Handler为null,直接返回
if (h == null) {
return;
}
synchronized (this) {
Message p = mMessages;
// Remove all messages at front.移除前面所有消息
while (p != null && p.target == h && p.what == what
&& (object == null || p.obj == object)) {
Message n = p.next;
mMessages = n;
// 释放消息
p.recycleUnchecked();
p = n;
}
// Remove all messages after front.移除后面所有消息
while (p != null) {
Message n = p.next;
if (n != null) {
if (n.target == h && n.what == what
&& (object == null || n.obj == object)) {
Message nn = n.next;
n.recycleUnchecked();
p.next = nn;
continue;
}
}
p = n;
}
}
}
下面的也是MessageQueue中的移除消息方法,其主要逻辑和上面方法基本一样,只是参数不同
void removeMessages(Handler h, Runnable r, Object object)
void removeCallbacksAndMessages(Handler h, Object object)
private void removeAllMessagesLocked() // 移除所有的消息,清空消息队列,private修饰
private void removeAllFutureMessagesLocked()// 移除所有的未处理消息,当消息队列的头Message.when大于当前时间,就调用removeAllMessagesLocked()方法。
8. 退出方法
// 有一个参数,表示是否安全退出,true表示安全退出
void quit(boolean safe) {
// 判断当前MessageQueue是否可以退出,如果是主线程就不能退出并抛出一个异常
if (!mQuitAllowed) {
throw new IllegalStateException("Main thread not allowed to quit.");
}
// 进入同步块
synchronized (this) {
// 该MessageQueue已经退出,直接返回
if (mQuitting) {
return;
}
// 将 mQuitting 设置为true,表示MessageQueue处于退出状态
mQuitting = true;
// 判断是否需要安全退出,然后调用不同的移除方法
if (safe) {
removeAllFutureMessagesLocked(); // 只会清空MessageQueue消息池中所有的延迟消息,并将消息池中所有的非延迟消息派发出去让Handler去处理
} else {
removeAllMessagesLocked(); // 把MessageQueue消息池中所有的消息全部清空,无论是延迟消息(延迟消息是指通过sendMessageDelayed或通过postDelayed等方法发送的需要延迟执行的消息)还是非延迟消息
}
// 调用native方法,并把native层当前的MessageQueue地址作为参数传递
nativeWake(mPtr);
}
}
9. 其他方法
增加和移除需要在空闲时间处理的事件
// 增加
public void addIdleHandler(@NonNull IdleHandler handler) {
if (handler == null) {
throw new NullPointerException("Can't add a null IdleHandler");
}
synchronized (this) {
mIdleHandlers.add(handler);
}
}
// 移除
public void removeIdleHandler(@NonNull IdleHandler handler) {
synchronized (this) {
mIdleHandlers.remove(handler);
}
}
发送一个同步阻碍消息
public int postSyncBarrier() {
return postSyncBarrier(SystemClock.uptimeMillis());
}
private int postSyncBarrier(long when) {
// Enqueue a new sync barrier token.
// We don't need to wake the queue because the purpose of a barrier is to stall it.
synchronized (this) {
final int token = mNextBarrierToken++;
final Message msg = Message.obtain();
msg.markInUse();
msg.when = when;
msg.arg1 = token;
Message prev = null;
Message p = mMessages;
if (when != 0) {
while (p != null && p.when <= when) {
prev = p;
p = p.next;
}
}
if (prev != null) { // invariant: p == prev.next
msg.next = p;
prev.next = msg;
} else {
msg.next = p;
mMessages = msg;
}
return token;
}
}
该消息用于阻碍同步Message消息执行,优先执行异步的Message。特点是变量 target 为 null,在 next()
方法中有用到。
在Android系统中的绘制过程中会使用这个方法:
在 ViewRootImpl
类中,会通过这个方式来保证主线程可以优先来执行接下来的绘制工作
@UnsupportedAppUsage
void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
if (!mUnbufferedInputDispatch) {
scheduleConsumeBatchedInput();
}
notifyRendererOfFramePending();
pokeDrawLockIfNeeded();
}
}
void doTraversal() {
if (mTraversalScheduled) {
mTraversalScheduled = false;
mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
if (mProfile) {
Debug.startMethodTracing("ViewAncestor");
}
performTraversals();
if (mProfile) {
Debug.stopMethodTracing();
mProfile = false;
}
}
}
MessageQueue类主要就分析这么多了,Handler机制的另外一个重要类Looper和Handler相关的一些知识在下一篇博客《Android Handler分析 (三) Looper详解和Handler其他知识》 中介绍。