一、Handler机制
创建一个Handler
//提示已过时
Handler handler = new Handler();
Handler handler = new Handler(Looper.myLooper());
隐式指定Looper的Handler初始化方法已被Android 11报过时,根据注释,是由于不指定Looper在一些场景下会导致任务丢失或程序崩溃,比如没有Looper的线程。
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
下面寻找这个Looper是在哪里初始化的
在ActivityThread.java#main中
public static void main(String[] args) {
...
Looper.prepareMainLooper();
...
Looper.loop();
}
Looper.java
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
根据ThreadLocal原理,调用Looper.prepare(boolean quitAllowed)时将该<ThreadLocal<Looper>,Looper>键值对设置到了当前线程的成员变量ThreadLocal.ThreadLocalMap threadLocals中,从而保证了每个线程对应唯一一个Looper,且不能被重复初始化,否则将抛出异常。而且Looper对象在初始化时也初始化了MessageQueue,并将当前线程保存在成员变量中。
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
以上初步实现了主线程对应sMainLooper,同时对应唯一一个MessageQueue。
下面分析Looper、MessageQueue、Handler如何运转起来
public static void loop() {
final Looper me = myLooper();
...
final MessageQueue queue = me.mQueue;
...
//死循环
for (;;) {
Message msg = queue.next();
...
try {
//将消息分发给相应Handler处理
msg.target.dispatchMessage(msg);
...
}
}
...
}
下面看Handler处理消息的过程
从sendMessage()、postDelayed()、post()都会调用到enqueueMessage
private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,
long uptimeMillis) {
msg.target = this;
msg.workSourceUid = ThreadLocalWorkSource.getUid();
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
下面看MessageQueue#enqueueMessage:
boolean enqueueMessage(Message msg, long when) {
...
synchronized (this) {
...
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 {
...
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;
}
...//唤醒线程本地方法
}
}
可以看到,消息入队时加了锁,保证了多个Handler向MessageQueue添加数据时的线程安全。添加消息首先判断队列中是否有消息,没有消息的时候需要对线程进行唤醒。如果不需要唤醒,则按照延迟时间入队。至于时间的判定,来自于Handler#sendMessageDelayed

本文深入剖析了Android中Handler、Looper和MessageQueue的工作原理,详细阐述了主线程Looper的初始化和Message的入队过程,以及如何保证线程安全。同时,介绍了View的绘制流程,从setContentView开始,讲解了如何将布局设置到窗口并进行UI更新的线程检查。最后,探讨了触摸事件的处理,包括ACTION_DOWN、ACTION_MOVE和ACTION_UP等不同阶段的关键操作。
最低0.47元/天 解锁文章
686

被折叠的 条评论
为什么被折叠?



