Android中的Handler机制分析(二) MessageQueue分析

来源:互联网 发布:手机注册淘宝账号流程 编辑:程序博客网 时间:2024/06/11 23:24

在上一篇博客《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 {@Overridepublic 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,直接返回falseif (h == null) {return false;}// 同步操作synchronized (this) {Message p = mMessages;// 遍历消息队列,获取每一个消息while (p != null) {// 将获取到的消息与参数进行比较if (p.target == h && p.what == what && (object == null || p.obj == object)) {// 找到了,返回truereturn true;}p = p.next;}// 没有找到,返回falsereturn false;}}// 判断方式一样,源码就不贴出来了boolean hasMessages(Handler h, Runnable r, Object object) {}


5.MessageQueue中的enqueueMessage()方法(非常重要)

在上一篇博客中,我们使用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设置为参数的whenmsg.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.nextprev.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中另一个非常重要的方法,next()方法,它返回下一个需要处理的Message

6.MessageQueue中的next()方法(非常重要)
next()方法的主要作用就是从消息队列中取出下一个需要执行的方法

Message next() {// 定义变量保存native代码中的消息队列地址值final long ptr = mPtr;// 如果地址值为0,表示队列不存在,返回nullif (ptr == 0) {return null;}// 保存IdleHandler对象的集合的大小,初始化时设置为 -1int 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为mMessgesMessage prevMsg = null;Message msg = mMessages;if (msg != null && msg.target == null) {// 从消息队列中找到一个异步消息 现在的msg就表示那个异步消息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的下一个为nullmsg.next = null;if (DEBUG) Log.v(TAG, "Returning message: " + msg);// 设置msg正在使用msg.markInUse();// 返回找到的Message(需要现在处理的Message)return msg;}} else {// 没有找到可执行的消息,设置 nextPollTimeoutMillis 为 -1nextPollTimeoutMillis = -1;}/**************走到这里表示没有找到可以返回的消息***************/// 如果队列需要退出,调用方法销毁队列,并返回nullif (mQuitting) {dispose();return null;}// 只有在第一次循环的时候才会走这步,因为 pendingIdleHandlerCount 的初始值是 -1if (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 handlerboolean 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();} else {removeAllMessagesLocked();}// 调用native方法,并把native层当前的MessageQueue地址作为参数传递nativeWake(mPtr);}}

Handler机制的另外一个重要类Looper和Handler相关的一些知识在下一篇博客《Android中的Handler机制分析(三) Looper分析和Handler其他知识》中介绍。


0 0
原创粉丝点击