Handler---4部曲---1. 总体流程
Handler---4部曲---2. ThreadLocal 存储主流程
Handler---4部曲---3. MessageQueue队列
Handler---4部曲---4.细节补充
一. 主线程Looper.loop()死循环阻塞了,为何Activity的里代码还能执行,为什么不会ANR.
- 看过Activity的启动流程就知道了, Activity的生命周期全部运行在handler中, 也属于一个msg, 包括一些点击事件等, 也是msg.
- ANR的判断, 并不是主线程loop里判断的,而是在别的地方.
二. Handler发送消息时,到底哪个线程的Looper处理的, 回调方法handleMessage在哪个线程?
由Hander初始化时的Looper对象决定的.
- 如下:无论在任何地方初始化Handler,最终回调运行在主线程.
new Handler(Looper.getMainLooper())
- 如下:最终回调运行在当前Handler初始化的线程.
new Handler(Looper.myLooper())
Handler的空参构造函数标记成已过时,就是为了让调用者明确,在哪个线程回调时.
三 主线程 什么时候进行休眠? 什么时候被唤醒?
关键标记: MessageQueue中的成员变量:;
mBlocked ---> true主线程休眠中 , false没休眠
通过上一篇文章我们知道, 主线程进入休眠的条件:
//取出的消息msg ---->包括同步或异步
msg==null || 没到msg执行的时间 && 没有空闲消息
怎么唤醒:
调用nativeWake方法即可唤醒,一共3个地方调用, 如下图:
1. enqueueMessage方法,msg入队的时候
加队列唤醒线程条件.png①. 当前状态休眠 && 新消息(同步或异步)可以马上执行的时候,需要唤醒.
②. 当前状态休眠 && 新消息不需要马上执行 && 队列头是同步屏障消息 && 新加进来的消息异步消息
2. removeSyncBarrier方法,删除异步消息的时候
3.quit方法, 放弃消息, 准备退出的时候
疑问:mQuitAllowed什么时候赋值的?
①. MessageQueue构造方法赋值
②. Looper中的构造方法赋值.
Looper构造方法.png
③. 主线程和子线程 Looper 初始化的区别
looper.prepare方法.png
四. 子线程和主线程消息处理有什么不一样的?
通过上面可以知道.
- Looper初始化的时候, 传入参数不同
- 主线程允许退出,子线程不允许退出
- next()方法返回值,子线程调用quit方法后,会唤醒当前线程,next()返回null, 会退出loop循环.
- 子线程无法处理mIdleHandlers空闲任务, 因为在next()里:
if (mQuitting) { 子线程会进入这里
return null;
}
...后面才是处理mIdleHandlers空间任务.
image.png
4.子线程使用完必须释放资源(任意一个), 否则会造成内存泄漏.
//mQueue.quit(false);
handler().getLooper().quit();
//mQueue.quit(true);
handler().getLooper().quitSafely();
五. 任何线程 ---> 指定子线程发送消息.
注意: 退出 释放内存
六. 如何发送 需要紧急处理的msg?
MessageQueue.next()方法可知,队列头是同步屏障消息时,优先处理异步消息.
image.png
所以关键有2步:
- 添加同步屏障消息到队列头
postSyncBarrier()
- 我们紧急处理的消息--->设置为异步消息
补充:
①. 方法调用,可能需要反射
②. 同步屏障消息,用完记得删除, 上一篇文章提到过
七. Message 里面的缓冲池.
-
取消息的时候, 直接从缓冲池里拿.
image.png -
释放的时候, 如果缓冲池没有满, 加到缓冲池最前面
image.png
网友评论