概述

Android 消息机制主要指的是 Handler 的运行机制及其所依赖的 MessageQueue 和 Looper 的工作过程,Handler、MessageQueue、Looper组成一个相互联系的整体。本文先从 MessageQueue 的源码来说明其实现原理。

MessageQueue 原理

MessageQueue ,顾名思义,意为消息队列,其操作主要有插入和读取。插入对应的方法为 enqueueMessage(),即往消息队列中插入一条消息,而读取对应next(),该方法会从消息队列中取出一条消息并将其从消息队列中删除。虽然 MessageQueue 的名字包含队列(Queue),但是其底层实现采用的是单链表,这是因为链表在插入和删除方面的性能好。下面看其源码实现。

boolean enqueueMessage(Message msg, long when) {       ... ...//省略        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;            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();                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);            }        }        return true;    }

enqueueMessage()中,Message 对象 p 代表下一个消息,对于新进来的消息,如果满足条件: p == null || when == 0 || when < p.when,那么就将它插在消息列表的最前面;否则,就按照消息触发的时间( when 字段)来插入消息。也就是说,消息的插入是按照时间顺序从小到大进行的。

接下来在看看获取消息的 next() 方法:

Message next()         .....//省略        int pendingIdleHandlerCount = -1; // -1 only during first iteration        // 1.如果nextPollTimeoutMillis=-1,一直阻塞不会超时。        // 2.如果nextPollTimeoutMillis=0,不会阻塞,立即返回。        // 3.如果nextPollTimeoutMillis>0,最长阻塞nextPollTimeoutMillis毫秒(超时)        //   如果期间有程序唤醒会立即返回。        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;                //如果target==null,那么它就是屏障,需要循环遍历,一直往后找到第一个异步的消息                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) {                    //如果有消息需要处理,先判断时间有没有到,如果没到的话设置一下阻塞时间,                    //场景如常用的postDelay                    if (now < msg.when) {                       //计算出离执行时间还有多久赋值给nextPollTimeoutMillis,                       //表示nativePollOnce方法要等待nextPollTimeoutMillis时长后返回                        nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);                    } else {                        // 获取到消息                        mBlocked = false;                       //链表操作,获取msg并且删除该节点                         if (prevMsg != null)                             prevMsg.next = msg.next;                        } else {                            mMessages = msg.next;                        }                        msg.next = null;                        msg.markInUse();                        //返回拿到的消息                        return msg;                    }                } else {                    //没有消息,nextPollTimeoutMillis复位                    nextPollTimeoutMillis = -1;                }                .....//省略    }

先说一下,MessageQueue 的数据结构为一个单向链表,Message 对象有个 next 字段保存列表中的下一个,MessageQueue 中的 mMessages 保存链表的第一个元素。

可以看到,next() 是一个无限循环的方法,读取消息时如果有消息就将该消息从消息列表中移除并返回该消息,否则就一直阻塞。

参考:

  • 深入理解 MessageQueue
  • Android多线程分析之四:MessageQueue的实现
  • Android消息机制(二):Message和MessageQueue

更多相关文章

  1. Android(安卓)FrameWork——Touch事件派发过程详解
  2. Android异步消息处理机制(源码分析+面试题)
  3. Android(安卓)FrameWork――Touch事件派发过程详解
  4. Android系统架构ABC
  5. Asynchronous HTTP Requests in Android(安卓)Using Volley
  6. Android中对Handle机制的理解
  7. 探究Android异步消息的处理之Handler详解
  8. Android中Handler源码解析(一)
  9. android 线程大集合

随机推荐

  1. Android地图尝试之两行代码调用高德地图
  2. dumpsys的使用笔记
  3. MAC中Android(安卓)Studio快捷键(一)
  4. Android前台服务 音乐播放器 前台服务
  5. (安卓/android)第一次开机扫描过程分析与
  6. Mac 下 下载Android源码步骤
  7. android分享功能的实现
  8. 【android入门】之Android中设置全屏的方
  9. android presentation实现双屏异显
  10. Android热更新之dx工具jar转换dex