Android 线程4件套 MessageQueue Message Looper Handler之MessageQueue


看了前面Looper章节之后,也许还是云里雾里的,但至少了解到Looper中每个Looper干了什么事,其中我们MessageLooper留下了两个问题。主要问题是Looper如何从MessageQueue中去取消息的。

那么我们先从MessageQueue如何压入消息开始:

MessageQueue是Message的一个收纳处,App通过Handler将Message压入到MessageQueue。

1. MessageQueue成员

    /** mimics 'this' synchronization lock */
    android::Mutex mLock;  //同步锁

    android::sp<Message> mMessages; //消息链表头;
    android::sp< GArrayList< IdleHandler > > mIdleHandlers; 空闲处理Handlers
    android::sp< Blob< android::sp<IdleHandler> > > mPendingIdleHandlers;
    bool mQuiting;    //是否暂停了
    bool mQuitAllowed;//是否允许暂停
    bool mBlocked;    //是否堵塞了

    // The next barrier token.
    // Barriers are indicated by messages with a null target whose arg1 field carries the token.
    int mNextBarrierToken;//Barrier的令牌

  public:
    android::sp<NativeMessageQueue> mNativeQueue;  //NativeQueue, 位于Jni层。

2. 接口
/**
	 * Add a new {@link IdleHandler} to this message queue.  This may be
	 * removed automatically for you by returning false from
	 * {@link IdleHandler#queueIdle IdleHandler.queueIdle()} when it is
	 * invoked, or explicitly removing it with {@link #removeIdleHandler}.
	 *
	 * <p>This method is safe to call from any thread.
	 *
	 * @param handler The IdleHandler to be added.
	 */
    void addIdleHandler(const android::sp<IdleHandler>& handler);

	/**
	 * Remove an {@link IdleHandler} from the queue that was previously added
	 * with {@link #addIdleHandler}.  If the given object is not currently
	 * in the idle list, nothing is done.
	 *
	 * @param handler The IdleHandler to be removed.
	 */
    void removeIdleHandler(const android::sp<IdleHandler>& handler);


	/**
	 * ctor
	 */
    MessageQueue(bool quitAllowed);
    virtual ~MessageQueue();

    android::sp<Message> next();

    void quit();
    int enqueueSyncBarrier(long long when);
    void removeSyncBarrier(int token);

    bool enqueueMessage(const android::sp<Message>& msg, int64_t when);

    bool hasMessages(const android::sp<Handler>& h);

    bool hasMessages(const android::sp<Handler>& h, int what, const android::sp<Object>& object);

    bool hasMessages(const android::sp<Handler>& h, const android::sp<Runnable>& r, const android::sp<Object>& object);

    void removeMessages(const android::sp<Handler>& h, int what, const android::sp<Object>& object);

    void removeMessages(const android::sp<Handler>& h, const android::sp<Runnable>& r, const android::sp<Object>& object);

    void removeCallbacksAndMessages(const android::sp<Handler>& h, const android::sp<Object>& object);

2.1. 先介绍一下IdleHandler。

IdlerHandler是定义在MessageQueue的一个内部类:

	/**
	 * Callback interface for discovering when a thread is going to block
	 * waiting for more messages.
	 */
    class IdleHandler:virtual public Object {
    DECLARE_DYNAMIC(IdleHandler);
      public:
        IdleHandler();
		/**
		 * Called when the message queue has run out of messages and will now
		 * wait for more.  Return true to keep your idle handler active, false
		 * to have it removed.  This may be called if there are still messages
		 * pending in the queue, but they are all scheduled to be dispatched
		 * after the current time.
		 */
        virtual bool queueIdle()=0;
    };


根据上下文意思和注释分析来看,IdleHandler是为了提高效率,当Looper在进入空闲等待状态前,如果应用程序注册了IdleHandler接口来处理一些事情,那么就会先执行这里IdleHandler,然后再进入等待状态。

 IdleHandler只有一个成员函数queueIdle,执行这个函数时,如果返回值为false,那么就会从应用程序中移除这个IdleHandler,否则的话就会在应用程序中继续维护着这个IdleHandler,下次空闲时仍会再执会这个IdleHandler。MessageQueue提供了addIdleHandler和removeIdleHandler两注册和删除IdleHandler。


2.2. 构造函数

MessageQueue::MessageQueue(bool quitAllowed):
      mPendingIdleHandlers(NULL),
      mQuiting (false),
      mQuitAllowed(quitAllowed),
      mBlocked(false) {
  mIdleHandlers = new GArrayList<IdleHandler>();//创建IdleHandler数组链表
  sp<NativeMessageQueue> nativeMessageQueue = new NativeMessageQueue();//创建NativeMessageQueue
  mNativeQueue = nativeMessageQueue;
}

2.3. 插入队列
bool MessageQueue::enqueueMessage(const sp<Message>& msg, int64_t when) {
  GLOGENTRY();
  if (msg->isInUse()) { //msg是否正在使用中
    return false;
  }
  if (msg->target == NULL) { //没有Target 
    return false;
  }
  bool needWake;
  {
    AutoMutex _l(mLock);  //同步锁
    if (mQuiting) {       //正在暂停中,那么不插入
      return false;
    }
    msg->when = when;
    sp<Message> p = mMessages;  //消息队列头
    if (p == NULL || when == 0 || when < p->when) { 
      /*
       *把Msg插在头部的情况:
       *--p是空的;
       *--message的When==0,也就是立即需要处理的,
       *--when < p->when,也就是when的时间最早
       */
      // New head, wake up the event queue if blocked.
      msg->next = p;
      mMessages = msg;
      needWake = mBlocked;  // new head, might need to wake up 是否需要wake要看目前是否已经堵塞住了。
    } else {
      /*这种情况是将msg插入在队列之中的,通常不需要执行wake动作;
       *
       */
      // 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();
      //p->target == Null表示MessageQueue头部存在一个barrier栏栅
      //也就是若p头部存在barrier且已经堵塞,而且msg是一个异步消息,这样才需要唤醒?为什么?
      sp<Message> prev;
      for (;;) {
        prev = p;
        p = p->next;
        if (p == NULL || when < p->when) {  //找到第一个p->when大于msg->when的结点
          break;
        }
        if (needWake && p->isAsynchronous()) { //若needWake为True,而且p中存在一个异步的消息,那么将needWake设置为false,这又是为什么
          needWake = false;
        }
      }
      msg->next = p;  // invariant: p == prev.next
      prev->next = msg; //插入消息
    }
  }
  if (needWake) { //若需要wake,那么执行NativeQueue的Wake动作,最后执行到了事件Looper的Wake中;
    if (mNativeQueue != NULL) {
      mNativeQueue->wake();
    }
  }
  return true;
}

2.4. 取出消息

sp<Message> MessageQueue::next() {
  int pendingIdleHandlerCount = -1;  // -1 only during first iteration
  int nextPollTimeoutMillis = 0;     //初次进来,将PollTimeOUt设置为0

  while (true) {
    if (nextPollTimeoutMillis != 0) {  
      IPCThreadState::self()->flushCommands();//这个没怎么看懂,应该是跟驱动交流下,刷新下信息
    }

    if (mNativeQueue != NULL) {
      mNativeQueue->pollOnce(nextPollTimeoutMillis); 
     /*
      *进入了事件Looper的 pollOnce,初次进来时,nextPollTimeoutMillis为0,Pollonce的poll_wait会立即返回,
      *如果后续的while循环中,发现有延时msg,那么nextPollTimeoutMillis > 0, pollonce也将通过epoll_wait消耗那部分的时间,然后返回;
      */
    }

    // synchronized (this)
    {
      AutoMutex _l(mLock); //同步锁
      if (mQuiting) { //如果已经暂停了,那么直接返回, Message Looper收到NULL信息之后,将会break出for循环。
        return NULL;
      }
      // Try to retrieve the next message.  Return if found.
      long long now = uptimeMillis(); //取出现在的时间
      sp<Message> prevMsg = NULL;
      const sp<Message> msg = mMessages; //取出队列
        // Stalled by a barrier.  Find the next asynchronous message in the queue.
        /*
         *若msg->target == NULL, 说明存在barrier,barrier的目的是,后面的同步消息将堵塞,异步消息可以拿出来执行,所以需要找出异步消息
        */
      if (msg != NULL && msg->target == NULL) {

        do {
          prevMsg = msg;
          msg = msg->next;
        } while (msg != NULL && !msg->isAsynchronous());//寻找异步消息
      }
      if (msg != NULL) {
      /*若msg !=NULL ,不管是异步的还是同步的 long long when = msg->when; if (now < msg->when) {
      *判定时间,看Message是否准备好了,若没有准备好,计算出下一次Message到时的时间;
      *到下一个触发时间的时候,我们再轮询到这里来,而中间的时间将通过pollOnce消耗掉 
      */
        long long when = msg->when;
        if (now < msg->when) {
          // Next message is not ready.  Set a timeout to wake up when it is ready.
          nextPollTimeoutMillis = (int) min(msg->when - now, INT_MAX);//计算下一次Message到时消息的时间
        } else {
          // Got a message.
          mBlocked = false;
          if (prevMsg != NULL) {
            prevMsg->next = msg->next;
          } else {
            mMessages = msg->next;
          }
          msg->next = NULL;
          if (false)
            GLOGV("MessageQueue Returning message: %s",
                  msg->toString()->string());
          msg->markInUse();
          return msg;
        }
      }else {
       /*
        *否则表示Messages中没有任何消息,设置nextPollTimeouMillis = -1,
        *表示pollOnce将需要无穷的等待,直到有事件唤醒
        */
       // No more messages.
        nextPollTimeoutMillis = -1;
      }

      // 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 Blob<sp<IdleHandler> >(
            max(pendingIdleHandlerCount, 4));
      }
      mPendingIdleHandlers = mIdleHandlers->toArray(mPendingIdleHandlers);
    }
    //既然需要等待了,那么执行注册了的那写IdleHandlers;
    // Run the idle handlers.
    // We only ever reach this code block during the first iteration.
    for (int i = 0; i < pendingIdleHandlerCount; i++) {
      const sp<IdleHandler> idler = (*mPendingIdleHandlers)[i];
      (*mPendingIdleHandlers)[i] = NULL;  // release the reference to the handler

      bool keep = false;
      // try {
      keep = idler->queueIdle();
      // } catch (Throwable t) {
      //    Log.wtf("MessageQueue", "IdleHandler threw exception", t);
      // }

      if (!keep) { //根据QueueIdle的返回值,删除或者保留该idler
        // synchronized (this)
        {
          AutoMutex _l(mLock);
          mIdleHandlers->remove(idler);
        }
      }
    }
    /*
     *执行完这些IdleHandler之后,线程下次调用nativePollOnce函数时,
     *就不设置超时时间了,因为,很有可能在执行IdleHandler的时候,
     *已经有新的消息加入到消息队列中去了,因此,要重置nextPollTimeoutMillis的值
     */
    // 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;
  }//继续轮询;

}


先说说Block

Block更改状态的情况:

1). 没有取到消息,即Message要么还没到时,要么为NULL,;且这时候,没有IdleHandler要处理,那么mBlocked设置为true;

2). 当我们取到了满足要求的消息,并准备返回之前,将mBlocked设置为false;

mBlocked将影响插入msg到MessageQueue时是否需要Wake动作
需要根据mBlocked来判定条件的条件的情况:

1). 当插入消息时,若发现msg需要插入到头部,那么wakeup将根据mBlocked来设置值,若mBlock为true这需要wake.

2). 若不是插入到头部,且MessageQueue目前是barrier状态,那么除非msg是第一个异步的消息,wake将设置为true;

    if (p == NULL || when == 0 || when < p->when) {
      // New head, wake up the event queue if blocked.
      msg->next = p;
      mMessages = msg;
      needWake = mBlocked;  // new head, might need to wake up
    } 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();//若msg是异步,且p是barrier,且mBlock状态
      sp<Message> prev;
      for (;;) {
        prev = p;
        p = p->next;
        if (p == NULL || when < p->when) {
          break;
        }
        if (needWake && p->isAsynchronous()) { //若还存在其他异步的,表示Msg不是第一个异步的,那么也不需要wake
          needWake = false;
        }
      }
      msg->next = p;  // invariant: p == prev.next
      prev->next = msg;
    }


这就是Looper中取出消息的一个过程分析;

总结一下:

a). MessageQueue在创建时,会创建一个NativeQueue

程序的主线程在进入消息循环过程前,会在Native中创建一个事件Looper, 该Looper中创建一Pipe,管道的作用是使得程序主线程在消息队列为空时可以进入空闲等待状态,并且使得当应用程序的消息队列有消息需要处理时唤醒应用程序的主线程。

b). 当Message Looper进入到MessageQueue::Next取消息时,先让NativeQueue进入到Pollonce,消耗掉nextPollTimeoutMillis的时间值:这个nextPollTimeoutMillis在后续循环中会根据Queue中Message的情况来设置不同的值;

c). MessageQueue尝试去取下一个消息,

若第一个消息是延时消息且未到时,那么更新nextPollTimeoutMillis,

若是Barrier消息,表示存在一个栏栅,栏栅后面的同步消息是不同执行的,那么取后面的异步消息;

若第一个消息不是barrier,且也到时了,那么去出来,将堵塞状态更新为false;

若第一个消息为NULL, 表示没有消息,那么更新nextPollTimeoutMillis = -1;

d). 若没有取到消息,那么进入到IdleHandler,

若IdlerHandler也不存在,那么将mBlock设置为true; 

若存在IdlerHandler,那么执行IdleHandler,等IdleHandler执行结束了,则可能这短时间Message满足要求了,那么将nextPollTimeoutMillis重置为0;

然后继续While循环;


2.5. enqueueSyncBarrier

enqueueSyncBarrier并不需要Wake动作

int MessageQueue::enqueueSyncBarrier(long long when) {
  // Enqueue a new sync barrier token.
  // We don't need to wake the queue because the purpose of a barrier is to stall it.
  //synchronized (this) {
  AutoMutex _l(mLock);
  const int token = mNextBarrierToken++;     //生成令牌
  const sp<Message> msg = Message::obtain(); //生成barrier消息
  msg->arg1 = token;                         //args记录token信息

  sp<Message> prev = NULL;
  sp<Message> p = mMessages;
  if (when != 0) {
    while (p != NULL && p->when <= when) {   //根据When信息找到插入的位置
      prev = p;
      p = p->next;
    }
  }
  if (prev != NULL) {  // invariant: p == prev.next
    msg->next = p;
    prev->next = msg;
  } else {
    msg->next = p;
    mMessages = msg;
  }
  return token;
}

2.6. removeSyncBarrier


void MessageQueue::removeSyncBarrier(int token) {
  // Remove a sync barrier token from the queue.
  // If the queue is no longer stalled by a barrier then wake it.
  bool needWake;
  AutoMutex _l(mLock);
  sp<Message> prev = NULL;
  sp<Message> p = mMessages;
  while (p != NULL && (p->target != NULL || p->arg1 != token)) { //根据target和token找到barrier的msg
    prev = p;
    p = p->next;
  }
  if (prev != NULL) {  
    prev->next = p->next;
    needWake = false;  //若barrier在queue的中间则不需要wake
  } else {  //barrier在Queueu的头部,那么需要唤醒
    mMessages = p->next;
    needWake = mMessages == NULL || mMessages->target != NULL;
  }
  p->recycle(); //将barrier回收

  if (needWake) {
    if (mNativeQueue != NULL) {
      mNativeQueue->wake(); //唤醒
    }
  }
}

2.7. Quit

void MessageQueue::quit() {
  if (!mQuitAllowed) {
    GLOGE("Main thread not allowed to quit.");
  }

  //synchronized (this) {
  AutoMutex _l(mLock);
  if (mQuiting) {
    return;
  }
  mQuiting = true;

  if (mNativeQueue != NULL) { //Quit之后需要进行Wake
    mNativeQueue->wake();
  }
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值