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(障碍物,屏障;界线)的标记(令牌)
/** * 这个接口是当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();}
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) {}
在上一篇博客中,我们使用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
- Android中的Handler机制分析(二) MessageQueue分析
- Handler,Looper,MessageQueue,android中的消息机制以及源码分析(二)
- Android消息机制:Looper、Handler、MessageQueue分析
- [Android源代码分析]Android消息机制,Handler,Message,Looper,MessageQueue
- Handler,Looper,MessageQueue,android中的消息机制以及源码分析(一)
- Android 消息机制 - Handler, Looper, Message, MessageQueue 的源码分析
- Android消息机制(Handler,Looper,MessageQueue)-源码分析
- Looper、MessageQueue、Handler机制简要分析
- Android中的Handler机制分析(一) Handler和Message分析
- Android源码分析——Looper,Messagequeue,Message,handler初始化及handler机制简介
- Android 源码分析——Looper,Messagequeue,Message,handler 初始化及 handler 机制简介
- Android Handler Looper MessageQueue原理分析
- android handler Looper MessageQueue源码分析
- Android Handler机制分析
- android消息处理机制学习(三)-Handler,Message,MessageQueue,Looper源码分析
- Android Handler消息机制源码分析——第一部分:Looper与MessageQueue
- Android开发知识(五)消息处理机制Handler+Looper+MessageQueue的原理分析(上)
- Android开发知识(六)消息处理机制Handler+Looper+MessageQueue的原理分析(下)
- nagios插件之监控日志中index增长情况
- 反思与感悟
- 总结 mysql error 1130 hy000:Host'localhost'解决方案
- Hexo学习(1) Mac中Hexo与GithubPages环境搭建
- 自圆其说并发编程之——认识线程开销
- Android中的Handler机制分析(二) MessageQueue分析
- stm32f070 软件复位
- 文章标题
- [代码实例][SQLServer]关闭连接
- 【Android】为 RecyclerView增加监听以及数据混乱的小坑
- 失败加载jni分享库/Failed to load the jni shared library
- BZOJ 3527[Zjoi2014]力 FFT
- NSURLSession使用说明及后台工作流程分析
- 最短路径—Dijkstra算法和Floyd算法