开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第9天,点击查看活动详情
3.消息队列的工作原理
- MessageQueue消息队列,负责入队和出队,储存Handler发送的消息,它是一个按Message的when的排序的优先队列。
- 虽然MessageQueue叫消息队列,但是它内部是用链表来实现的。
MessageQueue主要包含两个操作:插入和读取,读取操作本身会伴随删除操作,插入和读取对应的方法分别为enqueueMessage和next:
-
boolean enqueueMessage(Message msg, long when):往消息队列中插入一条消息
-
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
...
}
}