提出问题
说下Handler机制
主线程创建的Handler对象,构造里传入一个子线程的Looper,那么这个handler handleMessage()方法,工作的是线程是主线程的还是子线程的?
Looper通过MessageQueque取消息,消息队列是先进先出模式,那我延迟发两个消息,第一个消息延迟2个小时,第二个消息延迟1个小时,那么第二个消息需要等3个小时才能取到吗?
使用 Handler 需要注意什么?
Handler 机制介绍
主要有5个类
Handler 负责发消息和处理消息
Message 消息对象
MessageQueue 消息队列,负责存储消息对象 本质是优先队列
Looper 消息轮询器 负责从MQ中取消息并传给Handler,让其处理
ThreadLocal 保存Looper
发送消息
Handler 使用 sendMessage() 方法发送消息,
最后调用到 MessageQueue 的 enqueueMessage()方法,向队列里添加消息
这里有个关键点 Message 有个值 when(when = 当前时间戳+delay),添加消息的时候会将when的大小当做优先级将MessageQueue 重新排列,
轮训消息
Looper.loop();
接收并处理消息
Looper 会从 MessageQueue 中取出消息
然后会发现有这个逻辑 msg.target.dispatchMessage(msg); 其中 target 就是Handler
Handler 的 dispatchMessage() 方法 最终调用的是 handleMessage() 方法
handleMessage线程问题
可以倒着推,上图可以看到 Handler的handleMessage()方法 是在 Handler 的 dispatchMessage()中调用的我们可以查找下 dispatchMessage() 方法调用的时机
这里直接给出答案,dispatchMessage() 会再Looper的 loop() 方法中被调用,上面Message的target 就是发送Message的 Handler.
这个Message 是从 MessageQueue 取出来的,所以他跟 MessageQueue 在同一线程
全局搜索可以发现 这个MessageQueue是由Looper维护的 而Looper是Handler 构造函数传进来的,
结论
Handler跟其绑定的Looper 在同一个线程
ThreadLocal
ThreadLocal 内部有个 ThreadLocalMap 来存储对象 但是是非静态的 所以每个线程都各有一份
static 关键字修饰
Java 中 匿名内部类和非静态内部类都会隐式的持有一份对外部类的引用,而静态的内部类则不会包含对外部类的引用。
如上图这样给匿名类添加static,还会报warn
有下面3种解决方案,推荐使用第三种
创建 Handler对象 传入Callback
如上图 Java核心技术第10版给出的定义是:
如果构造参数的闭小括号后面跟一个开大括号,正在定义的就是匿名内部类。
所以 该方式是创建了一个对象,而非匿名内部类,所以不会持有外部类的引用
为Handler 指定Looper
自己继承Handler定义一个静态类
该方式是创建了静态内部类,这样就不会不会持有外部类的引用
小TIP:
这里会检测是否有传callback 若有传就不会走handleMessage了