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内部消息发送的学习,我们已经学完了,让我们实际创建学习一下吧!

更多相关文章

  1. Android应用程序键盘(Keyboard)消息处理机制分析(5)
  2. [转]android两次按返回键退出程序实现
  3. Android应用程序中模拟发送键盘触摸消息
  4. android 记录所有打开的Activity,退出程序
  5. android 彻底退出程序方法
  6. Android 4.0允许用户禁用所有系统自带程序
  7. NDK开发之环境的搭建和开发第一个NDK程序

随机推荐

  1. 开发Blog整理
  2. Android面试题集锦
  3. 上接系出名门Android(8) - 控件(View)之T
  4. (M)Android消息处理机制分析之Handler类解
  5. [Android] 监听系统网络连接打开或者关闭
  6. 如何裁剪android 系统?
  7. Android(安卓)Studio更新Android(安卓)SD
  8. Android字体表
  9. android 界面自适应屏幕尺寸相关
  10. Android全屏处理