从源码的角度分析Android中的Handler机制的工作原理
程序员文章站
2022-07-14 15:09:42
...
通过对源码的查看,特此记录Android中handler机制的工作方式
我们要在Android中使用Handler机制,必须要经过如下三个过程:
- 在一个线程调用 Looper.prepare() 来创建一个Looper. (主线程不需要,因为源码中在Activity创建的时候已经调用过一次了)
- 调用 new Handler() 创建一个 Handler.
- 调用 Lopper.lopp() 开始进入死循环不停的从 MessageQueue 中取出消息然后发送给 Handler 处理.
下面我们从源码的角度去查看为什么要经过这三个过程Handler机制才能正常工作:
源码的 Looper.prepare() 干了什么:
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));
}
- 我们看到,在最后一行中的 sThreadLocal.set(new Looper(quitAllowed)) 给一个ThreadLocal变量设置了一个 Lopper 对象,这样就造成了这个线程和这个 Lopper 关联起来了.
从源码中发现,在Handler机制中的 MessageQueue 是由 Lopper 来维护的, 为什么? 因为源码中有这么一段:
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
所以经过源码中的步骤,一个线程就和一个 Lopper 关联起来了,而这个 Lopper 又维护着一个 MessageQueue .
源码的 new Handler() 干了什么:
public Handler(Callback callback, boolean async) {
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
这是 Lopper.myLopper 的源码:
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
- 天哪噜,我们看到,,,之前设置给那个 ThreadLocal 变量的 Lopper 在这里 马上就被使用 sThreadLocal.get() 方法被 Handler 获取到了.
- 然后我们看到,获取到 Looper 之后马上又获取了 Looper 的 MessageQueue.
所以通过这一步我们看到, 源码帮我们把 我们之前调用的 Looper.prepare 创建的 looper 对象和一个 Handlder 关联起来了,并且Handler 还获取了由 Looper 维护的 MessageQueue! 接下来就可以干大事了!!!
源码的 Lopper.lopp() 干了什么(比较多,贴精华部分):
public static void loop() {
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue;
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
try {
msg.target.dispatchMessage(msg);
end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
}
这里是 Message 类的部分源码,方便理解上面的代码:
class Message implements Parcelable {
Handler target;
}
- 我们看到,在loop方法中,也同样是调用了 myLooper 获取了 第一步创建的一个和线程关联的 looper
- 然后获取了这个 looper 的 messagequeue ,之后就会进入一个死循环.
- 在这个死循环中,会不停的去调用 message.next ,来获取下一个 message (message队列使用链表实现的.)
- 获取到一个 message后,就会调用 message 的 target.dispatchMessage 来发送消息到handler, 通过上面 message 类 ,我们看到 target变量就是一个 Handler.
到了这里,有读者肯定会问,这个 Message 中的 Target 是怎么来的呢, 这个 Message 是如何和一个 Handler 关联起来的呢?
- 我在这里解释一下,无论我们通过 handler 的post 方法 还是 sendMessage 方法来发送一条消息,在源码中,都会跳转到 Handler 中的如下代码中:
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
首先注意这一段代码是 Handler 中的源码 ,看方法名字就知道,是往之前获取的 MessageQueue中插入消息, 然后最重要的就是
msg.target = this 这句, 通过这句话,这个 Message 就和这个Handler关联起来了,然后在 loop 中就会把这个 message 发送给这个 handler 进行处理!!!
总结
- 通过上面对源码的分析,我们知道要让Handler机制能够正常工作,必须要有一个looper,然后Handler会的往这个looper的MessageQueue中发送消息,之后再调用loop不停的去MessageQueue中取出消息发送给和这个Message关联的Handler进行处理.
- 比如我们在线程中调用了 Looper.prepare 那么这个 Looper 就会和该线程关联,然后我们在其他线程中调用 Handler 发送消息, 这个消息自然会被插入到创建 Handler 的那个线程的 MessageQueue 中 ,然后再让 Handler 进行处理 ,这样就实现了 Android中的线程通信原理.
- 同时我们也可以从 java 引用的角度来思考 Handler 机制是如何实现的:
- 第一步 : Lopper.prepare() 会导致一个线程的 ThreadLocalMap 中持有了一个 Lopper 的引用.
- 第二步 : new Handler() 导致 Handler 会持有当前运行这句话的那个线程的 Looper 的引用, 然后当我们调用 handler 发送 message 时, 每一条 message 都会持有 handler 的引用(即 message 的 target 成员变量)
- 第三步 : Lopper.loop() 会从从当前正在运行这句话的线程中获取 Lopper 引用, 然后进入死循环获取 Looper 中的 message, 然后调用 message.target.dispatchMessage() 最关键的就是这一步,无论这个 Handle r在哪个线程创建,关键的是当前正在运行这句话的线程获取了 handler 的引用, 从而通过 handler 的引用调用了 handler 的成员方法, 从而实现了把 Message 发送到了目标线程.
这里顺便说一下为什么在子线程中创建一个 Handler 而没有调用 Looper.prepare 会报错的原因,其实很简单,就是源码中的一段:
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
如果有误,欢迎评论指导,谢谢!!
推荐阅读
-
android的消息处理机制(图文+源码分析)—Looper/Handler/Message
-
android的消息处理机制(图文+源码分析)—Looper/Handler/Message
-
Android消息通信机制Handler详解,Handler,Looper,MessageQueue,源码解析,讲解这几个类怎么配合工作的
-
Android的消息机制Handler原理分析
-
从源码的角度分析Android中的Handler机制的工作原理
-
很容易理解的Android AsyncTask源码与工作原理分析
-
Android Handler机制的工作原理详析
-
Android ListView工作原理完全解析,带你从源码的角度彻底理解
-
[转载]android的消息处理机制(图+源码分析)——Looper,Handler,Message
-
Android开发知识(八):Android事件处理机制:事件分发、传递、拦截、处理机制的原理分析(中)