一,简述

      MessageQueue在Android中指消息队列,顾名思义就是存放消息的消息池,但是它的内部实现并不是队列而是一个单链表,可能是单链表的删除和插入比较有优势吧MessageQueue的内部对消息的主要操作就是插入,读取删除,不具备处理消息的能力。

二,源码分析

1,重要属性信息介绍

  // True if the message queue can be quit.private final boolean mQuitAllowed;@SuppressWarnings("unused")private long mPtr; // used by native codeMessage mMessages;private final ArrayList<IdleHandler> mIdleHandlers = new ArrayList<IdleHandler>();private SparseArray<FileDescriptorRecord> mFileDescriptorRecords;private IdleHandler[] mPendingIdleHandlers;private boolean mQuitting;// Indicates whether next() is blocked waiting in pollOnce() with a non-zero timeout.private boolean mBlocked;

mQuitAllowed:是否允许MessageQueue退出

mPtr:可以理解成是C/C++的指针,是一个内存地址,当为0的时候说明消息队列被释放了

mMessage:表示存储消息链表的头Head

mQuitting:当前队列是否处于正在退出状态

mBlocked:是否被阻塞

2,构造方法

  MessageQueue(boolean quitAllowed) {mQuitAllowed = quitAllowed;mPtr = nativeInit();}

可以看到创建MessageQueue的时候就需要指定MessageQueue是否可以退出。nativeInit();是一个Jni方法用来初始化mPtr

3,enqueueMessage(Message msg,long when)

 boolean enqueueMessage(Message msg, long when) {msg.target 指消息机制中的Handlerif (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;boolean needWake;  将新消息放在链表头部的条件:1,队列为空 ;2,接收到的新消息需要立即处理:when = 0;3,新消息等待处理的时间比链表队头要短这时候只需要将新消息的next指向当前链表的头部,让mMessages指向新消息,如果当前的队列是阻塞的就唤醒队列if (p == null || when == 0 || when < p.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();  遍历处理新消息的位置:prev指向p的上一个消息,p开始向队尾移动,如果新消息需要执行的等待时间小于p所指向的消息,就将新消息放在prev和p之间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.nextprev.next = msg;}// We can assume mPtr != 0 because mQuitting is false.如果需要唤醒队列,调用nativeWake(mPtr);唤醒队列if (needWake) {nativeWake(mPtr);}}return true;}

enqueueMessage();是MessageQueue的核心方法,主要功能是向MessageQueue中插入消息

4,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; mPtr == 0说明消息队列被释放了if (ptr == 0) {return null;}int pendingIdleHandlerCount = -1; // -1 only during first iterationint nextPollTimeoutMillis = 0;for (;;) {if (nextPollTimeoutMillis != 0) {Binder.flushPendingCommands();}阻塞操作,等待nextPollTimeoutMillis时长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 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;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 {// No more messages.nextPollTimeoutMillis = -1;}如果消息队列正在处于退出状态返回null,调用dispose();释放该消息队列// 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) {// 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 handlerboolean 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();方法是MessageQueue的和新方法也是比较难理解的一个方法。主要做的工作是从消息队列中取出消息。

 void removeMessages(Handler h, int what, Object object) {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;}}}

移除消息队列中的消息removeMessage();这个方法有两个重载方法,大致逻辑是一样的。在这个方法中有两个while循环,对这两个while讲解比较详细的博客。

上面说过MessageQueue是一个链表,链表分两种:带头节点的不带头节点的。这两种链表的遍历方式不同:不带头节点的链表中,第一个元素需要单独处理,然后将后续部分当作是带头节点的链表使用while循环遍历。MessageQueue是不带头节点的链表,所以我们可以看到有两个while循环。

第一个while循环:如果队列中的第一个Message的target,what,object与指定的handler,what,object相同,删除第一个元素。后续部分就成了带头节点的链表。第二个循环删除链表中后续中符合条件的Message

以上就是对MessageQueue的全部分析内容,有不足的地方或是有误的地方欢迎大家提出指正。

Android 消息机制之深入学习MessageQueue相关推荐

  1. Android消息机制(Handler、MessageQueue、Looper)详细介绍

    Android的消息机制其实在android的开发过程中指的也就是Handler的运行机制,这也就引出了android中常见的面试问题: 简述Handler.Looper.MessageQueue的含 ...

  2. android自定义队列,Android 消息机制(一)消息队列的创建与循环的开始 Looper与MessageQueue...

    写在前面 本文基于Android 7.1.1 (API 25)的源码分析编写 与之前的触摸事件分发机制分析的文章一样,Android系统机制的分析中关键的一环就是事件消息的处理.之前也说过,Andro ...

  3. Android 系统(177)---Android消息机制分析:Handler、Looper、MessageQueue源码分析

    Android消息机制分析:Handler.Looper.MessageQueue源码分析 1.前言 关于Handler消息机制的博客实际上是非常多的了. 之前也是看别人的博客过来的,但是过了一段时间 ...

  4. Android 进阶14:源码解读 Android 消息机制( Message MessageQueue Handler Looper)

    不要心急,一点一点的进步才是最靠谱的. 读完本文你将了解: 前言 Message 如何获取一个消息 Message.obtain() 消息的回收利用 MessageQueue MessageQueue ...

  5. Android消息机制Handler用法

    这篇文章介绍了Android消息机制Handler用法总结,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧 1.简述 Handler消息机制主要包括: Messa ...

  6. 理解 Android 消息机制

    本人只是Android小菜一个,写技术文章只是为了总结自己最近学习到的知识,从来不敢为人师,如果里面有不正确的地方请大家尽情指出,谢谢! 本文基于原生 Android 9.0 源码来解析 Androi ...

  7. 【腾讯Bugly干货分享】经典随机Crash之二:Android消息机制

    为什么80%的码农都做不了架构师?>>>    本文作者:鲁可--腾讯SNG专项测试组 测试工程师 背景 承上经典随机Crash之一:线程安全 问题的模型 好几次灰度top1.top ...

  8. android消息池,回转寿司你一定吃过!——Android消息机制(构造)

    消息机制的故事寿司陈放在寿司碟上,寿司碟按先后顺序被排成队列送上传送带.传送带被启动后,寿司挨个呈现到你面前,你有三种享用寿司的方法. 将Android概念带入后,就变成了Android消息机制的故事 ...

  9. android handler的机制和原理_一文搞懂handler:彻底明白Android消息机制的原理及源码

    提起Android消息机制,想必都不陌生.其中包含三个部分:Handler,MessageQueue以及Looper,三者共同协作,完成消息机制的运行.本篇文章将由浅入深解析Android消息机制的运 ...

  10. Android 消息机制详解(Android P)

    前言 Android 消息机制,一直都是 Android 应用框架层非常重要的一部分,想更加优雅的进行 Android 开发,我想了解消息机制是非常必要的一个过程,此前也分析过很多次 Handler ...

最新文章

  1. setsockopt 设置socket 详细用法
  2. 局部变量、全局变量、堆、堆栈、静态和全局
  3. SAP 电商云 Spartacus UI Angular Component 动态创建的单步调试
  4. 分享一个点赞超过100的漂亮ASP.NET MVC蓝色界面框架
  5. language support图标在哪里?怎么消失了?
  6. 机器学习经典算法笔记——梯度下降算法
  7. 聪明女人的七个致富之道,学会它你也能成为人人羡慕的小富婆
  8. linux系统组成以及运行模式
  9. c语言圆周率天书解释,c语言天书圆周率的计算及分析.doc
  10. 虚拟蜜罐-honeyd安装部署
  11. Bootstrap免费字体和图标网站
  12. 【案例实践】Python多元线性回归、机器学习、深度学习在近红外光谱分析中的实践应用
  13. 动物miRNA靶基因本地预测(三)—— 靶基因预测与结果分析
  14. 小程序 报错 errcode: 40029, errmsg: invalid code, hints: [ req_id: HQd79a0747th31 ]
  15. MySQL全量同步和增量同步-
  16. Android 绘制渐变色
  17. 问卷调查小程序功能清单
  18. 小米业绩再创季度新高,股价或再次上涨,米粉或实现赚一倍的愿望
  19. Express jade
  20. matlab主要功能,matlab主要功能

热门文章

  1. C++实现走迷宫算法
  2. 弱监督学习综述-周志华(ML论文阅读笔记1)
  3. 二维向量叉乘的简单介绍及应用
  4. 三维全景拍摄这些技巧很实用
  5. FAT 文件系统代码分析--文件系统挂载篇
  6. 工具 - 屏幕录像专家7.5注册机
  7. 国税计算机安全管理制度,武汉市国家税务局关于印发《计算机中心机房管理制度》的通知...
  8. 【C语言:丹尼斯·里奇的不朽遗产 】
  9. linux下字符终端某些按键无法输入解决方法
  10. 计算机动画的教育应用研究,计算机动画技术在高校CAI课件制作中的应用研究