「这是我参与11月更文挑战的第17天,活动详情查看:2021最后一次更文挑战」
Handler机制原理
1.Looper
loop()
public static void loop() {
//...
//返回sThreadLocal存储的Looper实例
final Looper me = myLooper();
//拿到该looper实例中的消息队列
final MessageQueue queue = me.mQueue;
//...
for (;;) {
//取出一条消息,如果没有消息则阻塞等待
Message msg = queue.next();
if (msg == null) return;
try {
//Msg的target其实就是handler对象
msg.target.dispatchMessage(msg);
}
//释放资源
msg.recycleUnchecked();
}
}
上述是loop的源码,此处省略部分代码。
loop()方法,不断从MessageQueue中取消息,无则阻塞,等待消息。有则交给消息的target属性(handler对象)的dispatchMessage方法去处理。
上面介绍了 msg.target其实就是Messager所属的Handler。
后面会具体介绍Handler并对此进行说明。
2.Message
Message 是线程通信中传递的消息,使用what进行消息的区分,使用 arg1、arg2、obj、data 进行数据的传递,参数 target它决定了 Message 所关联的 Handler。上面也提到了这一点,后续会进行分析。
public final class Message implements Parcelable {
//...
Handler target;
Message next;
//...
}
每个Message都有一个指向自己的引用,所以它采用链表方式进行存储,如果不考虑Message的事件,如果有新的Message传入,只需要将MessageQueue的最后一个Message的引用指向传入的Message。
3.MessageQueue
MessageQueue 负责管理消息队列,通过一个单链表的数据结构来维护。
这里主要介绍三个方法:
这个方法功能是将消息插入到消息队列中。
boolean enqueueMessage(Message msg, long when) {
if (msg.target == null) {
throw new IllegalArgumentException("Message must have a target.");
}
//在这里使用synchronized同步代码块,防止多线程导致的异步操作混乱。
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) {
// New head, wake up the event queue if blocked.
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;
prev.next = msg;
}
if (needWake) {
nativeWake(mPtr);
}
}
return true;
}
这部分主要可以分为四部分。
-
如果当前MessageQueue是处于退出状态的,那么要直接返回false,即入队失败。
-
MessageQueue是根据Message所执行的时间来进行插入的。
-
下面即是进行Message链表的插入操作,需要注意的是,MessageQueue中有一个mMessages引用,始终指向Message链表的头节点
-
即是一个链表的插入操作。