自我总结:
从主体结构来讲主要是三部分,looper,Messagequeue,handle,looper中存在一个死循环不断从信息队列中取出信息交给对应的handle进行处理,主线程中的looper在App启动的时候就会启动,具体代码在activityThread的main方法中,因此在主线程中使用handle的时候不需要去管looper的创建,在子线程中使用handle需要调用looper.prepare.和lopper.loop来创建对应的looper,而looper和线程是一一对应的,一个线程只能拥有一个loop,这个实现是通过ThreadLocal来实现的,threadlocal简单的来说它线程私有的一个数据副本(这边可以扩展讲下threadlocal内存泄漏的原因以及优化处理),它是线程自身维护的一个key-value集合,这边key就threadlocal的对象,value就存放对应的值,thread创建对应的loop的threadlocal对象是静态final的变量,在内存空间里是唯一的存在,让key是唯一的存在,这样在线程创建loop的时候进行判断该key是否存在对应的值,如果有就抛出异常来。这样保证了thread有唯一的looper。messagequeue是一个存在优先级的单向信息队列,在messagequeue中它保存的是一个message的对象,而message对象它持有next message对象的引用 所以可以通过不断调用next我们可以遍历到整个message队列,所以队列是单向的,优先级实现的原理需要看put方法,handle的所有sendmessage方法最后调用都是sendmessageattime 这里会给每个message设置一个延时执行时间,在信息存入队列时从头开始遍历比较执行时间,如果比对方小就插入到对方前面,从而实现了优先级的队列,handle可能导致的内存泄漏也就在于此,一个延迟消息在messagequeue中存放,message会持有handle的引用,而handle是一个匿名内部类,在java中匿名内部类默认持有外部类的引用,最后导致handle所在的activity被持有而导致不能释放。如果当message队列为空或者当前最新的message延迟处理的话,当前线程会进入休眠状态,而这个休眠状态是通过native方法来实现的 底层调用了liunx的休眠方法,而休眠的时间由当前任务来决定的。handle为什么能跨线程处理任务的原因需要考虑java虚拟机的一些知识,(可以扩展讲java虚拟机)堆是线程共享的,所以message队列数据就存放在堆中,这就实现了handle跨线程通信的基础了,这里多线程并发操作肯定需要一个锁来维护资源的安全性,这里通过synchronized来实现多线程对信息队列访问的安全机制,(这边可以扩展锁相关信息)不管是添加还是取出message都会重置looper的休眠状态。message取出后调用对应的handler处理这样整个流程完成了。
总结知识点:
1.handler处理整体的结构。
2.handler为什么能跨线程通信的。
3.为什么looper里面一个死循环不会导致卡死问题。
4.handler处理信息的优先级如何实现的。
5.handler在多线程情况下怎么实现线程安全。
6.looper和线程是如何一对一进行绑定的。
7.为什么支持new 出多个handler。