1 对象创建
1.1 Looper 创建
应用启动时会在ActivityThread的mian方法里进行lLooper的创建具体方法为


这里具体初始化的方法为prepare(false)
下面的同步方法是为了确保一个线程中只有单个Looper,重复初始化时会出现异常


ThreadLocal可以理解为一个Map集合 这里是以线程为key,Looper为Value 以键值对的形式存储线程对应的Looper
创建Looper对象之前 会先从ThreadLocal中获取当前线程key的对象,如果获取到了则当前线程中已经有对应的对象,不能重复创建抛出异常如果没有则调用Looper的私有构造方法将其放入ThreadLocal.

这是Looper的构造方法因为是私有所以只能通过prepare来进行创建,在prepare做了线程为key的检索确保了一个线程中只有一个Looper为我们在多线程中创建线程唯一对象提供了思路
在构造方法中将MessageQueue的对象创建出来,每个Looper都有对应的MessageQueue对象
至此Looper创建完成
1.2 MessageQueue的创建
由上面代码可以看出MessageQueue是在Looper的构造方法中创建,由于Looper的线程唯一的创建方式所以MessageQueue在单个线程中也只有一个唯一的对象
1.3 Handle的创建

如图所示,Handle有3种创建方式
handle的创建方式用的是以下构造方法

hanldle1的创建方式用的是以下构造方法

handle2的创建构造方法与handle1相同

最终都会进入同一个底层的构造方法
在此方法中可以看到handler中通过mLooper = Looper.myLooper()拿到了当前线程的Looper对象
接下来会对Looper对象进行非空判断拿到Looper对象后拿到了Looper的MessQueue对象
以及对回调方法callback进行赋值
1.4 Message
Message对象是在进行Handler通信中直接new出来的一个对象通过
Message msg = Message.obtain()拿到
可以看到obtain中会尝试拿空闲的Message对象进行复用如果没有会直接返回一个新的对象
2 信息的发送
信息的发送方式有以下几种
可以传入Message对象也可以只传入what
只传入what时也会创建Message对象
最终都会进入enqueueMessage方法
这里为msg.target进行了赋值
从上图可知Message在添加进MessageQueue队列之前也将当前的Handler对象存入;
通过sendMessageAtTime拿到了Handler初始化时从Looper中获得的MessageQueue对象
最终调用MessageQueue的enqueueMessage方法将Message对象添加进MessageQueue中

3 信息的取出与处理
在ActivityThread的main方法中在Looper.prepareMainLooper()之后还执行了一个Looper的方法
可以看到 Loop中法中先拿到了本线程的Looper通过本线程的Looper对象拿到了MessageQueue对象
内部维护了一个for死循环通过queue.next()取出消息
在时间比对操作之后
最终会执行msg.target.dispatchMessage(msg)
从之前的代码中可以看出msg.target是消息在放入MessageQueue之前将生成消息的Handle对象赋值进去,所以此方法是回调Handle的dispatchMessage方法
可以看出此方法有3种回调逻辑,对应Handle的3种创建方式
handle对应2
handle1对应3
handle2对应1
hanlde的创建方式在传入时会将Handler.Callback赋值给mCallBack,当消息执行完毕时会进行2进行回调返回true或者false没有任何影响,因为返回false的话会执行图标记为3的handleMessage方法,此方法在源码中为空实现
hanlde1在构建时没有传入参数,所以只能走到3
/**
* Subclasses must implement this to receive messages.
*/
public void handleMessage(@NonNull Message msg) {
}
这个handleMessage在源码中是空的实现,但是在handle1构建的时候重写了handleMessage方法,所以这个方法也能正常执行
handle2在日常使用时通常是使用post方法
post方法中还是会调用sendMessage方法
通过getPostMessage方法获取一个Message对象并将Runnable赋值给message的callback属性满足diapatchMessage方法中的条件1
private static void handleCallback(Message message) {
message.callback.run();
}
将run方法在handle的创建线程中执行掉
至此 Hanlder执行完成
4 总结
应用启动时在AcitivyThread的main方法中通过Loop.prepare进行了Looper与MessageQueue对象的创建,通过Looper.loop方法启动内部的for死循环从MessageQueue中通过.next()方法获取Message对象,最终通过Mesage中的handle对象执行dispatchMessage的回调方法,实现跨线程的功能
Handle在创建时会拿到当前线程的Looper对象,通过Loop对象拿到MessageQueue的对象通过enqueueMessage方法将Mesage对象放入MessageQueue中
5 子线程Handler实现
将代码添加几行日志
发现Loop方法一直没有结束可以确定loop方法内部维护的确实是死循环
结束子线程Looper释放Thread资源
通过代码发loop的死循环中有这样的判断条件
当消息队列执行了quit方法时循环关闭 Looper中有quit()的方法
执行MessageQueue的quit方
测试一下 

执行成功run方法执行完毕线程销毁
那主线程的Looper能不能也这样停止呢
测试代码


查看源码发现这个异常是在MessageQueue中的quit()方法中抛出,主线程不能被quit

主线程的loop为什么不会被死循环阻塞


native方法实现
实现流程图

本文详细分析了Handler的源码,包括Looper、MessageQueue、Handler的创建过程,以及信息的发送、取出和处理机制。在Android应用启动时,ActivityThread的main方法创建Looper和MessageQueue,通过Looper.loop()的死循环来不断处理Message,实现跨线程通信。Handler在创建时获取当前线程的Looper,并通过enqueueMessage()将Message放入MessageQueue。同时,文中探讨了如何在子线程中停止Looper以及主线程Looper为何无法直接quit()。

872

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



