Handler如何通过sendMessage(Message msg)方法将新消息加入当前消息队列(二)

这里假设我们是通过Handler 的 sendMessage(Message msg) 来发送消息的

首先进入 sendMessage 方法

    public final boolean sendMessage(Message msg)
        {
           return sendMessageDelayed(msg, 0);//注意第二个参数传入的是整数 0
        }


   /**
     * Enqueue a message into the message queue after all pending messages
     * before (current time + delayMillis). You will receive it in
     * {@link #handleMessage}, in the thread attached to this handler.
     *
     * @return Returns true if the message was successfully placed in to the
     *         message queue.  Returns false on failure, usually because the
     *         looper processing the message queue is exiting.  Note that a
     *         result of true does not mean the message will be processed -- if
     *         the looper is quit before the delivery time of the message
     *         occurs then the message will be dropped.
     */
    public final boolean sendMessageDelayed(Message msg, long delayMillis)
    {
        if (delayMillis < 0) {
            delayMillis = 0;
        }
        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
    }


我们来看一下 sendMessageDelayed 这个方法,通过该方法的注释我们也可以了解到它的作用。这个方法会向消息队列中插入一条新的消息,也就是消息入队,重点来关注一下消息入队的时间。

看下面的注释:

after all pending messages * before (current time + delayMillis).

大概翻译过来就是 在所有即将处理的消息之后,在  current time + delayMillis 这个时间点之前 让消息入队。

delayMilis 就是我们需要让这个消息延迟多久之后发送,如果我们通过sendMessage(Message msg)这个方法来发送消息的话,默认延迟的时间是 0,也就是delayMillis=0,显然这个 current time 就是  SystemClock.uptimeMillis()  返回的时间。

进入SystemClock 查看该方法:

/**
     * Returns milliseconds since boot, not counting time spent in deep sleep.
     *
     * @return milliseconds of non-sleep uptime since boot.
     */
    @CriticalNative
    native public static long uptimeMillis();

uptimeMillis()方法返回的就是 从开机开始到现在的时间总数,以ms为单位,其中不包括系统深度睡眠的时间

网上介绍这个方法的文章也很多,可以自己百度一下。下面是Google官方文档,感兴趣的可以了解下

https://developer.android.google.cn/reference/android/os/SystemClock.html?hl=en

扫描二维码关注公众号,回复: 13654831 查看本文章

我们接着往下走,其实不论通过哪种方法发送消息最终都会走到下面的这个方法里面

    /**
     * Enqueue a message into the message queue after all pending messages
     * before the absolute time (in milliseconds) <var>uptimeMillis</var>.
     * <b>The time-base is {@link android.os.SystemClock#uptimeMillis}.</b>
     * Time spent in deep sleep will add an additional delay to execution.
     * You will receive it in {@link #handleMessage}, in the thread attached
     * to this handler.
     *
     * @param uptimeMillis The absolute time at which the message should be
     *         delivered, using the
     *         {@link android.os.SystemClock#uptimeMillis} time-base.
     *
     * @return Returns true if the message was successfully placed in to the
     *         message queue.  Returns false on failure, usually because the
     *         looper processing the message queue is exiting.  Note that a
     *         result of true does not mean the message will be processed -- if
     *         the looper is quit before the delivery time of the message
     *         occurs then the message will be dropped.
     */
    public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
        MessageQueue queue = mQueue;//就是文章(一)中介绍的Handler对应的mQueue
        if (queue == null) {
            RuntimeException e = new RuntimeException(
                    this + " sendMessageAtTime() called with no mQueue");
            Log.w("Looper", e.getMessage(), e);
            return false;
        }
        return enqueueMessage(queue, msg, uptimeMillis);
    }

注意注释中对于参数 uptimeMillis 的描述,它确定了发送该消息的精确时间。

接下来进入 enqueueMessage ,该方法最终进入了MessageQueue的同名方法中

    private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        msg.target = this;//指定了该消息的target为本Handler
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);//调用MessageQueue的方法
    }

我们详细看一下MessageQueue 的 enqueueMessage方法 ,该方法里包含了消息入队的核心代码

    boolean enqueueMessage(Message msg, long when) {
       ......

        synchronized (this) {
            ......
            
            msg.markInUse();//标记该消息正在使用中
            //when 就是上面传入的 SystemClock.uptimeMillis() + delayMillis
            msg.when = when;//when代表了该消息发送的精确时间 
            Message p = mMessages;//将p指向消息队列的头部
            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{//上面提到的 三种情况 均不满足说明我们需要将消息插入消息队列中的某个位置(在消息头之后)
                needWake = mBlocked && p.target == null && msg.isAsynchronous();
                Message prev;
                for (;;) {// 通过一个死循环来寻找消息插入的位置(其实就是通过时间来判断的)
                    prev = p;// 注意每循环一次 prev 指针都会指向当前的 p 指向的那个消息
                    p = p.next;// 这里移动 p 的位置到它的下一个消息,而此时 prev 仍然指向 p 原来的位置
                    if (p == null || when < p.when) {
                        //如果到了消息的队尾或者找到了比我们要发送消息的时间晚的那个消息就退出循环
                        break;
                    }
                    if (needWake && p.isAsynchronous()) {
                        needWake = false;
                    }
                }
                msg.next = p; // invariant: p == prev.next
                prev.next = msg;// 将我们要发送的消息放入 prev 和 当前 p 所指向的消息中间的位置
            }

            // We can assume mPtr != 0 because mQuitting is false.
            if (needWake) {
                nativeWake(mPtr);
            }
        }
        return true;
    }

if (p == null || when == 0 || when < p.when) {//这三种情况看下面的分析
                // New head, wake up the event queue if blocked.

以下三种情况均需要把我们要发送的这个消息放在消息队列的头部

p==null  表示消息队列为空

when=0 表示需要立刻发送该消息

when<p.when 表示该消息发送的时间早于头部的消息

好了,代码中的注释已经很详细,到此分析就结束了,欢迎各路大神批评指正!

猜你喜欢

转载自blog.csdn.net/lollo01/article/details/103817756
今日推荐