Android的消息机制(三)

95 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第9天,点击查看活动详情

3.消息队列的工作原理

  • MessageQueue消息队列,负责入队和出队,储存Handler发送的消息,它是一个按Message的when的排序的优先队列。
  • 虽然MessageQueue叫消息队列,但是它内部是用链表来实现的。

MessageQueue主要包含两个操作:插入和读取,读取操作本身会伴随删除操作,插入和读取对应的方法分别为enqueueMessage和next:

  1. boolean enqueueMessage(Message msg, long when):往消息队列中插入一条消息

  2. Message next() :消息队列中取出一条消息并将其从消息队列中移除

enqueueMessage和 next方法的部分源码: enqueueMessage的主要操作就是单链表的插入操作

boolean enqueueMessage(Message msg, long when) {//将Messages插入消息队列
    ...
   msg.when = when;//指定消息应该被处理的时间
   ...
   for (;;) {//将当前消息对象保存到消息队列中的一个合适的位置
            prev = p;
            p = p.next;
            if (p == null || when < p.when) {
                break;
            }
            if (needWake && p.isAsynchronous()) {
                 needWake = false;
             }
    }//最终的结果是:消息队列是按when来排序的
    ...
    nativeWake(mPtr);//通过本地方法实现对处理等待状态的底层线程
    ...
}

next方法是一个无限循环的方法。如果消息队列中没有消息,那么next方法可以阻塞在这里,

当有新的消息到来时,next方法会返回这条消息并将其中单链表中移除。

Message next() {//取出一个合适的Message对象,可能不会立刻返回
    ...
    nativePollOnce(ptr, nextPollTimeoutMillis);//本地方法,会导致可能处理等待状态,但不会阻塞主线程
    ...
    Message msg = mMessages;//取出消息队列中的第一个消息
    ...
    return msg;//返回
    ...
}

4.Looper的工作原理

Looper在Android的消息机制中扮演着消息循环的角色。

Looper为一个线程开启一个消息循环,创建MessageQueue,负责循环取出Message Queue里面的当前需要处理的Message,也就是说,它会一直不停地从MessageQueue中查看是否会有新消息,如果有新消息就会交给对应的Handler进行处理,处理完后,将Message缓存到消息池中以备复用,否则就一直阻塞在那里,Looper退出后,Handler发送消息会失败,线程会立刻终止。 常用方法:​

Looper.prepare():为当前线程创建一个Looper。

Looper.loop():开启消息循环.

Looper.getMainLooper():获取主线程的Looper。

Looper.quit()直接推迟Looper

Looper.quitSafely()设定一个退出标记,然后把消息队列中的已有消息处理完毕才安全地退出。

如何为一个线程创建Looper?

thread {
  Looper.prepare()
  val handler:Handler=MyHandler(this)
  Looper.loop()
 }

loop方法的部分源码:

public static void loop() {
    final Looper me = myLooper();//得到looper对象
    ...
    for (;;) {//无限循环
         ...
         Message msg = me.mQueue.next(); // 从消息队列中取出消息
         ...
         msg.target.dispatchMessage(msg);//调用Handler去分发并处理消息
         ...
         msg.recycleUnchecked();//回收利用Message
         ...
    }
}