1、将Message放入消息队列前,将Message中的target指向当前handler
2、放入消息队列
p == null,说明原本是空队列,when == 0 说明当前消息可以立即执行,when < P.when说明第一个元素到了执行时间所以如果队列阻塞需要唤醒
3、如果不满足上述三个条件,就对新的msg寻找插入点
插入到即将处理的msg后面
4、如果需要就唤醒线程
5、Looper的初始化
这里需要掌握ThreadLocal知识点
这里我们简单说下,首先sThreadLocal是个静态变量,所以不同的Looper对象其sThreadLocal是同一个,这样sThreadLocal.get() != null就可以确定已经初始化过,从而抛出异常
而其set的过程
所以一个线程只会有一个looper否则就会抛出运行时异常,因为在ThreadLocalMap中的key是sThreadLocal是唯一的,那么不同线程是否会抛出运行时异常 呢,显然 不会,因为从t.threadLocals说明threadLocals只是线程的一个成员变量。
这里ThreadLocalMap也与其他Map不同,一个是节点继承了弱引用,一个是hash取值
接下来看下Looper.loop()
先从消息队列中获取msg,如果不到执行时间则阻塞,如果到了就返回msg,如果为空就无限阻塞,直到有新的消息到来唤醒线程
接下来要回到主线程了,所以日志记录下消息执行的时间,性能优化、ANR均可设置logging
上文已经说到target就是我们放入消息队列的handler
那么到这里在说handler内存泄漏已经一目了然了,因为looper在主线程的在与队列绑定是消息队列是不允许退出的,那么主线程的虚拟机栈帧的局部变量表(GCRoot)中会持有looper,持有消息队列,sMainLooper是个静态变量也能当做GCRoot持有handler,而handler是匿名内部类隐士持有activity,这样activity就无法回收