目录
1、背景
1、我们都知道Android只允许在主线程中进行UI的更新操作,那么为什么不允许在子线程中更新UI呢?
答:这是因为Android的UI空间是线程不安全的,如果多线程并发访问UI,可能导致UI控件处于一个不可预期的状态。
2、那么为什么不给UI控件添加锁机制呢?
答:首先加上锁会让UI的更新逻辑变得复杂;其次锁机制会降低更新UI的效率。
2、简介
稍微了解过Handler原理的人,都知道Handler的实现其实和 Message、MessageQueue、Looper这三个类共同完成的。
- Message :信息对象的实体类;
- MessageQueue:存储Message对象的类,内部使用单链表的信息存储多个Message对象。
- Looper :会开启个死循环,不断地从MessageQueue中的单链表中遍历Message对象,然后将Message对象分发给Handler处理。
- Handler:作用就是将Message对象放入MessageQueue的单链表中,然后处理从Looper获取到的Message对象。
3、使用
当我们在主线程使用Handler的时候,一般都直接new 一个Handler就可以正常使用了。但是正常启用一个Handler流程需要调用Looper的prepare()和loop()方法。如下的代码:
那么主线程中的Handler为什么不需要调用这两个方法呢?
答:这是因为在主线程,也就是ActivityThread线程中,提前为我们调用了这两个方法。
4、源码详解
接下来的内容,是我在源码的基础上,简化了代码,自己实现的简易版Handler,方法名与源码都是对应的。如果有兴趣看源码可以对照这看,这样理解起来比较容易。
4.1、第一步:Looper.prepare()
prepare()的源码很简单,他就是利用ThreadLocal将我们new出来的Looper对象保存到了当前的所在的线程中。
ThreadLocal.ThreadLocalMap内部其实是一个数组保存着Looper。ThreadLocalMap是自定义的哈希映射,仅适用于维护线程局部值。 没有操作导出到ThreadLocal类之外。 该类是包私有的,以允许声明Thread类中的字段。
这样在我们new Thread("handler线程:")线程就有了Looper对象。
4.2、第二步:new Handler()
new Handler() 的实现其实很简单,就是实现了Callback接口来为后面处理消息做准备,而这里同时保存了Looper中的MessageQueu