萝卜小姐-Handler之系列sendMessage学习

sendMessage方式学习

  • sendMessage作用
  • sendMessage主要方法以及源码学习
    • sendMessage(Message)
    • sendMessageDelayed(@NonNull Message msg, long delayMillis)
    • sendMessageAtTime(@NonNull Message msg, long uptimeMillis)
    • enqueueMessage(msg, uptimeMillis)
  • sendMessage系列其他方法
    • sendEmptyMessage(int what)
    • sendEmptyMessageDelayed(int what, long delayMillis)
    • sendEmptyMessageAtTime(int what, long uptimeMillis)
    • sendMessageAtFrontOfQueue(@NonNull Message msg)
    • executeOrSendMessage(@NonNull Message msg)

萝卜小姐-Handler之系列sendMessage学习_第1张图片

sendMessage作用

MessageQueue是一种单向链表数据结构,Message中有一个next属性指向队列中下一条消息,队列排序是根据Message的when字段(消息延迟时间)来排序的,调用handler.sendMessage(msg)发送的消息.

sendMessage主要方法以及源码学习

sendMessage(Message)

/** 在当前时间之前的所有挂起消息之后,将消息推送到消息队列的末尾。它将在{@link#handleMessage}中,在附加到此处理程序的线程中接收。
  *如果消息已成功放入消息队列,@return返回true。失败时返回false,通常是因为处理消息队列的looper程序正在退出。
  */
  public final boolean sendMessage(@NonNull Message msg) {
        return sendMessageDelayed(msg, 0);
    }
  • 由代码调用可知sendMessage() 内部调用的是sendMessageDelayed(msg,delayMillis),
  • delayMillis = 0,

下一步,我们先来看sendMessageDelayed(@NonNull Message msg, long delayMillis)

sendMessageDelayed(@NonNull Message msg, long delayMillis)

/* 在所有挂起的消息之后将消息推送到消息队列的末尾
*在(current time + delayMillis)之前。它将在{@link#handleMessage}中接收,
*在附加到此处理程序的线程中。
*@return如果消息成功放入消息队列。失败时返回false,通常是因为
*正在退出处理消息队列的循环程序。
*/
 public final boolean sendMessageDelayed(@NonNull Message msg, long delayMillis) {
        if (delayMillis < 0) {
            delayMillis = 0;
        }
        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
    }
  • 由代码调用可知sendMessageDelayed() 内部调用的是sendMessageAtTime(msg,uptimeMillis),
  • uptimeMillis = SystemClock.uptimeMillis() + delayMillis,

下一步,我们先来看sendMessageAtTime(@NonNull Message msg, long uptimeMillis)

sendMessageAtTime(@NonNull Message msg, long uptimeMillis)

/**
*在绝对时间(以毫秒为单位)之前,在所有挂起的消息之后将消息排入消息队列uptimeMillistime-base是{@link安卓系统时钟}.深度睡眠时间将增加执行的额外延迟。您将在{@link#handleMessage}中,在附加到此处理程序的线程中接收它。
*@param uptimemill是使用{@链接传递消息的绝对时间安卓系统时钟}time-base。
*如果消息已成功放入消息队列,@return返回true。失败时返回false,通常是因为处理消息队列的循环程序正在退出。注意,结果为true并不意味着消息将被处理——如果在消息传递时间之前循环器退出,那么消息将被丢弃。
*/
 public boolean sendMessageAtTime(@NonNull Message msg, long uptimeMillis) {
        MessageQueue queue = 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);
    }

enqueueMessage(msg, uptimeMillis)

sendMessageAtTime()内部调用的是enqueueMessage(),下面我们看一下Handler 的enqueueMessage()方法

 private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,
            long uptimeMillis) {
        msg.target = this;
        msg.workSourceUid = ThreadLocalWorkSource.getUid();

        if (mAsynchronous) {
         /* If true, the handler calls {@link Message#setAsynchronous(boolean)} 
          *for each {@link Message} that is sent to it or {@link Runnable} that is posted to it. 
          */
          msg.setAsynchronous(true);
          
        }
        return queue.enqueueMessage(msg, uptimeMillis);
    }

代码内容也很简单,调用了MessageQueue 的enqueueMessage().我们来看一下

/* 承接Handler发送消息部分,往队列中插入消息 */
  boolean enqueueMessage(Message msg, long when) {
        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.");
        }

/*  可以在任何线程中调用handler.sendMessage(msg3)发送消息,此处使用synchronized同步机制保证多线程并发时消息队列不会错乱 */
        synchronized (this) {
        /* 如果调用了Looper.quit()退出后,消息不会被插入 */
            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;/* when表示消息应该发送的时间,该时间=发送消息时距离手机启动毫秒数+消息延迟发送时间 */
            
            Message p = mMessages;/* 队列头部的消息对象 */
            boolean needWake;
            /***************************************下面是message 进入messageQueue的核心内容**********************************************/
           /* 队列头部元素为null(空队列) || 消息延迟时间 == 0 || 消息延迟时间 小于 头部队列的延迟时间 */
           /* Handler.sendMessage(),它的最小值为0,表示消息需要立刻处理,如果不为0表示是延时消息,该时间值越小,则消息越早被取出处理 */
            if (p == null || when == 0 || when < p.when) {
                // New head, wake up the event queue if blocked.
                msg.next = p;/* 新队头消息的next指向老的队头消息,由此可见这里是一个链表 */
                mMessages = msg;/* mMessages指向新的头部消息 */
                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插入到队列中,前后进行交换 */
                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;
    }

总结:

  • sendMessageAtTime()的time = sendMessageDelayed()的time + SystemClock.uptimeMillis();
  • 消息进入队列是一个以时间排序的链表
  • sendMessage()内部是将延迟时间=0,直接插入在链表的头部
  • sendMessage -> sendMessageDelayed -> sendMessageAtTime -> enqueueMessage -> MessageQueue.enqueueMessage

下面我们继续来看看其他的消息发送方式

sendMessage系列其他方法

sendEmptyMessage(int what)

 /**
     * 发送只包含what值的消息
     *  
     * @return 如果消息已成功放入消息队列,则返回true。失败时返回false,通常是因为处理消息队列的循环程序正在退出
     */
    public final boolean sendEmptyMessage(int what) {
        return sendEmptyMessageDelayed(what, 0);
    }

sendEmptyMessageDelayed(int what, long delayMillis)

 /**
     * 发送只包含what值的消息,该值将在指定的时间段过后传递。
     * @see #sendMessageDelayed(android.os.Message, long) 
     * 
     * @return  如果消息已成功放入消息队列,则返回true。失败时返回false,通常是因为处理消息队列的循环程序正在退出
     */
    public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
        Message msg = Message.obtain();
        msg.what = what;
        return sendMessageDelayed(msg, delayMillis);
    }

sendEmptyMessageAtTime(int what, long uptimeMillis)

 /**
     *发送只包含what值的消息,该消息将在特定时间传递。
     * @see #sendMessageAtTime(android.os.Message, long)
     *  
     * @return  如果消息已成功放入消息队列,则返回true。失败时返回false,通常是因为处理消息队列的循环程序正在退出
     */

    public final boolean sendEmptyMessageAtTime(int what, long uptimeMillis) {
        Message msg = Message.obtain();
        msg.what = what;
        return sendMessageAtTime(msg, uptimeMillis);
    }

sendMessageAtFrontOfQueue(@NonNull Message msg)

 /**
     *
     *  在消息队列前面对消息进行排队,以便在消息循环的下一次迭代中处理。您将在{@link#handleMessage}中,
     * 在附加到此处理程序的线程中接收它。此方法只在非常特殊的情况下使用——它很容易导致消息队列不足、导致排序问题或产生其他意外的副作用
     * @return  如果消息已成功放入消息队列,则返回true。失败时返回false,通常是因为处理消息队列的循环程序正在退出
     */
    public final boolean sendMessageAtFrontOfQueue(@NonNull Message msg) {
        MessageQueue queue = 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, 0);/*  直接插入在链表头部 */
    }

executeOrSendMessage(@NonNull Message msg)

  /**
     *如果在该处理程序对应的同一线程上调用消息,则同步执行消息,否则{@link#sendMessage将其推送到队列}
     * @return  如果消息已成功放入消息队列,则返回true。失败时返回false,通常是因为处理消息队列的循环程序正在退出
     * @hide 
     */
    public final boolean executeOrSendMessage(@NonNull Message msg) {
        if (mLooper == Looper.myLooper()) {
            dispatchMessage(msg);
            return true;
        }
        return sendMessage(msg);
    }
  

当当当,关于Hander内部消息发送的学习,我们已经学完了,让我们实际创建学习一下吧!

你可能感兴趣的:(Android,源码,android)