Skip to content
Able Blog
Home
Others
  • Home
      • 学习笔记
          • Android
            • 简历_赵思琦_Android_5年经验
                • Handler
                  • 01. handler整体架构方案原理
                    • 02. Message源码分析
                      • 03. Looper源码分析
                        • 04. ThreadLocal的使用及源码解析文章
                          • 05. MessageQueue源码解析
                            • 同步Message
                              • 异步Message
                                • Barrier
                                  • Next()方法分析
                                    • enqueueMessage() 入队,存入消息
                                    • 06. Handler源码解析
                                      • 07. 源码阅读总结
                                        • 08. Carson Handler总结的机制源码解析
                                          • 09. handler 内存泄漏的原因

                                      05. MessageQueue源码解析

                                      author iconAblecalendar icon2022年4月14日category icon
                                      • Android
                                      tag icon
                                      • Handler
                                      • 学习笔记
                                      word icon约 886 字

                                      此页内容
                                      • 同步Message
                                      • 异步Message
                                      • Barrier
                                      • Next()方法分析
                                      • enqueueMessage() 入队,存入消息

                                      # 05. MessageQueue源码解析

                                      在looper中调用MessageQueue方法。

                                      MessageQueue作为最核心的组件,其存储消息和取出消息都有不同的情况处理 消息分类 Message 有关于同步与否的flag, 0同步 1异步 Message.setAsynchronous()

                                      # 同步Message

                                      默认情况下消息都是同步的,使用Message.obtain方法获取的消息都是同步

                                      # 异步Message

                                      消息队列被阻塞时,异步消息可以正常执行

                                      # Barrier

                                      可阻塞消息队列。 MessageQueue有生产这种消息的专属方法postSyncBarrier。 用于信号同步场景。

                                      # Next()方法分析

                                        Message next() {
                                              // 如果消息循环已经退出并被释放,则返回此处。 如果应用程序在不支持的退出后尝试重新启动循环器,则可能会发生这种情况。
                                              final long ptr = mPtr;  //mPtr在MessageQueue构造里被初始化,来自于Native方法mPtr =nativeInit();
                                              if (ptr == 0) {
                                                  return null;
                                              }
                                      
                                              int pendingIdleHandlerCount = -1; // -1 仅在第一次迭代期间
                                              int nextPollTimeoutMillis = 0; //下一次轮训超时毫秒
                                              for (;;) {
                                                  if (nextPollTimeoutMillis != 0) { //超时
                                                      Binder.flushPendingCommands(); //施放挂起的对象引用
                                                  }
                                      
                                                  nativePollOnce(ptr, nextPollTimeoutMillis); //-1表示无限阻塞 一个非静态回调。JNI方法,作用是否阻塞当前方法
                                      
                                                  synchronized (this) {
                                                      // Try to retrieve the next message.  Return if found.
                                                      final long now = SystemClock.uptimeMillis(); //从开机到现在的毫秒数
                                                      Message prevMsg = null;
                                                      Message msg = mMessages;
                                                      
                                                      //Handler==null,从尾部节点取到最后一条Message和倒数第二条
                                                      if (msg != null && msg.target == null) {
                                                          // Stalled by a barrier.  Find the next asynchronous message in the queue.
                                                          do {
                                                              prevMsg = msg;  //倒数第二条
                                                              msg = msg.next; //倒数第一条Message 
                                                          } while (msg != null && !msg.isAsynchronous());
                                                      }
                                                      if (msg != null) {
                                                          if (now < msg.when) { //触发响应的时间大于当前时间,就是没准备好
                                                              // 下一条消息没有准备好。 设置超时以在它准备好时唤醒。
                                                              nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                                                          } else {
                                                              // Got a message.
                                                              mBlocked = false;
                                                              //从尾部节点取出Message。 
                                                              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;
                                                      }
                                      
                                                      // 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 handler
                                      
                                                      boolean 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;
                                              }
                                          }
                                      
                                      1
                                      2
                                      3
                                      4
                                      5
                                      6
                                      7
                                      8
                                      9
                                      10
                                      11
                                      12
                                      13
                                      14
                                      15
                                      16
                                      17
                                      18
                                      19
                                      20
                                      21
                                      22
                                      23
                                      24
                                      25
                                      26
                                      27
                                      28
                                      29
                                      30
                                      31
                                      32
                                      33
                                      34
                                      35
                                      36
                                      37
                                      38
                                      39
                                      40
                                      41
                                      42
                                      43
                                      44
                                      45
                                      46
                                      47
                                      48
                                      49
                                      50
                                      51
                                      52
                                      53
                                      54
                                      55
                                      56
                                      57
                                      58
                                      59
                                      60
                                      61
                                      62
                                      63
                                      64
                                      65
                                      66
                                      67
                                      68
                                      69
                                      70
                                      71
                                      72
                                      73
                                      74
                                      75
                                      76
                                      77
                                      78
                                      79
                                      80
                                      81
                                      82
                                      83
                                      84
                                      85
                                      86
                                      87
                                      88
                                      89
                                      90
                                      91
                                      92
                                      93
                                      94
                                      95
                                      96
                                      97
                                      98
                                      99
                                      100
                                      101
                                      102
                                      103
                                      104
                                      105
                                      106

                                      # enqueueMessage() 入队,存入消息

                                          boolean enqueueMessage(Message msg, long when) {
                                              if (msg.target == null) {
                                                  throw new IllegalArgumentException("Message must have a target.");
                                              }
                                      
                                              synchronized (this) {
                                                  if (msg.isInUse()) {
                                                      throw new IllegalStateException(msg + " This message is already in use.");
                                                  }
                                      
                                                  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) {
                                                     // 新头节点,如果阻塞则唤醒事件队列。
                                                      msg.next = p;
                                                      mMessages = msg;//传入的节点为新头结点
                                                      needWake = mBlocked;
                                                  } else {
                                                      // 插入到队列中间。 通常我们不必醒来
                                                       // 向上事件队列,除非队列头部有障碍
                                                       // 并且消息是队列中最早的异步消息。
                                                      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;
                                                  }
                                      
                                                  // 我们可以假设 mPtr != 0 因为 mQuitting 是false的。
                                                  //唤醒队列
                                                  if (needWake) {
                                                      nativeWake(mPtr);
                                                  }
                                              }
                                              return true;
                                          }
                                      
                                      1
                                      2
                                      3
                                      4
                                      5
                                      6
                                      7
                                      8
                                      9
                                      10
                                      11
                                      12
                                      13
                                      14
                                      15
                                      16
                                      17
                                      18
                                      19
                                      20
                                      21
                                      22
                                      23
                                      24
                                      25
                                      26
                                      27
                                      28
                                      29
                                      30
                                      31
                                      32
                                      33
                                      34
                                      35
                                      36
                                      37
                                      38
                                      39
                                      40
                                      41
                                      42
                                      43
                                      44
                                      45
                                      46
                                      47
                                      48
                                      49
                                      50
                                      51
                                      52
                                      53
                                      54
                                      55
                                      edit icon编辑此页open in new window
                                      上次编辑于: 2022/4/17 23:10:35
                                      贡献者: zsqan
                                      上一页
                                      04. ThreadLocal的使用及源码解析文章
                                      下一页
                                      06. Handler源码解析
                                      默认页脚
                                      Copyright © 2022 Able