源码已经分析完了,再来总结一波。
1. 关于message缓存池:
1. android工程师充分利用了JAVA的高级语言特性:即类种持有着一个类自身的属性作为经典数据结构中的链表的next指针,以静态属性属于类本身的特性实现了链表的表头。
2. 为什么要有message缓存池?
说白了就是message功能简单,但使用量大,所以回收用过的message很有必要:可以减少重复创建引起的资源浪费,而且他的回收成本很低。
3. 谁来回收message?
我们知道,通过Message.obtain()可以使用message缓存池,这是取;在看源码时,Looper在分发message给target后(这时候message已经完成了他的使命:成功作为载体,传递了消息内容),就直接回收了。
附:message的回收时机:在消息队列中remove掉msg后;单次loop结束之后;开发者主动调用msg的recycle()后。
2. 关于阻塞
MessageQueue维持的消息队列换个messge缓存池的原理一样,每次消息出队时如果没有合适的待取出消息就会阻塞线程等待有合适的消息再唤醒处理。
而MessageQueue实现的方式并不是通过java,而是通过jni调用了native层的C++代码(C++代码实现了一套Looper+MessageQueue+handler)。阻塞线程的方式是调用Linux监听文件描述符ePoll实现的。
3. 为什么实用handler实现线程间通信?
android是事件性驱动的系统,刚创建一个应用程序时,其主线程就会被创建一个Looper来不断接受各种事件,所有我们打个一个应用程序什么都不操作,这个程序就可能是阻塞状态(因为他没有事件可处理)。反之,我们在主线程进行耗时操作,导致主线程一个在执行这个耗时操作,而无法处理其他事务导致界面卡顿,就有可能引发ANR了。
4.关于looper
每个handler必须对应一个looper。
主线程在应用程序启动后,就自动的创建了Looper对象(我们通过getMainLooper就能获取到),不需要手动创建。
而我们在子线程new handler时,如果不传入指定的looper,那么looper会默认绑定当前创建handler的线程的looper,没有looper会报错。所以在子线程要开启handler,要先创建looper,并开启looper循环,即调用loop().
5. looper死循环为什么不会导致应用卡死?
点击桌面图标第一次启动activity后,会最终走到ActivityThread的main方法,在main方法中创建了Looper(looper有创建了消息队列)来处理主线程的消息,然后Looper.loop()会进入死循环,之后包括activity的生命周期和其他事务都是通过loop方法执行的。
UI线程的主要方法就是消息循环,一旦循环退出,app也就退出了。 Looper.loop()可能会引起主线程的阻塞(这要看他执行的是什么事务,耗不耗时),但只要消息循环没有阻塞,能一直处理发过来的事务,就不回ANR.
真正引发ANR的不是主线程的阻塞,而是主线程的Looper消息处理过程中发生了任务阻塞。,而不能实时的响应用户的操作,及时刷新UI导致的。即阻塞与ANR没有必然关系,虽然主线程在没有消息处理的时候是阻塞状态, 但是只要保证在有新消息时能及时响应、立即处理,就不回ANR。
总结:应用卡死和Looper的死循环没有比绕关系,应用在没有消息处理时,是在睡眠,释放线程;卡死是ANR,而Looper是睡眠。