《android开发艺术探索》读书笔记(十)--Android的消息机制
接上篇《android开发艺术探索》读书笔记(九)--四大组件
No1:
消息队列MessageQueue的内部存储结构并不是真正的队列,而是采用单链表的数据结构来存储消息列表,因为单链表在插入和删除上比较有优势
No2:
ThreadLocal可以在不同的线程中互不干扰地存储并提供数据,通过ThreadLocal可以轻松获取每个线程的Looper。
No3:
线程默认是没有Looper的,如果需要使用Handler就必须为线程创建Looper。
No4:
我们经常提到的主线程,也叫UI线程,它就是ActivityThread,ActivityThread被创建时就会初始化Looper,这也是在主线程中默认可以使用Handler的原因。
No5:
系统为什么不允许在子线程中访问UI呢?
1)因为Android的UI控件不是线程安全的,如果在多线程中并发访问可能会导致UI控件处于不可预期的状态
2)如果系统对UI控件的访问加上锁机制有两个缺点
21)会让UI访问的逻辑变得复杂
22)锁机制会降低UI访问的效率,因为锁机制会阻塞某些线程的执行
No6:
1)当某些数据是以线程为作用域并且不同线程具有不同的数据副本的时候,就可以考虑采用ThreadLocal。比如Looper、ActivityThread、以及AMS中
2)ThreadLocal另一个使用场景是复杂逻辑下的对象传递,比如监听器的传递。因为参数传递会使程序设计糟糕,而静态变量不具有可扩充性
No7:
为何不同线程访问同一个ThreadLocal得到的数据是不一样的?
因为不同线程访问同一个ThreadLocal的get方法,ThreadLocal内部会从各自的线程中取出一个数组,然后再从线程中根据当前ThreadLocal的索引去查找出对应的value值。
No8:
Android消息机制:
1)ThreadLocal工作原理:set方法、put方法、get方法(table[index+1]=value)
2)消息队列(MessageQueue)工作原理:插入enqueueMessage、读取并删除next(一个无限循环的方法)
3)Looper工作原理:构造方法(创建一个MessageQueue,保存当前线程对象),Looper.prepare()(创建一个Looper),Looper.loop()(开启消息死循环,跳出循环唯一方式是next方法返回null),quit方法(终止循环,否则一直等待)
4)Handler工作原理:sendMessage发送消息、dispatchMessage-->handleMessage处理消息
No9:
Looper.getMainLooper可以在任何地方获取到主线程的Looper
No10:
当Looper的quit方法被调用时,Looper就会调用MessageQueue的quit或者quitSafely方法来通知消息队列退出,当消息队列被标记为退出状态时,它的next方法就会返回null。
No11:
Handler发送消息的过程仅仅是向消息队列中插入了一条消息,MessageQueue的next方法就会返回这条消息给Looper,Looper收到消息后就开始处理了,最终消息由Looper交由Handler处理,即Handler的dispatchMessage方法会被调用,这时Handler就进入了处理消息的阶段。
No12:
主线程消息循环:Android的主线程就是ActivityThread,主线程的入口方法为main,在main方法中系统会通过Looper.prepareMainLooper()来创建主线程的Looper以及MessageQueue,并通过Looper.loop()来开启主线程的消息循环。主线程的Handler是ActivityThread.H
No13:
主线程的消息循环模型:
ActivityThread通过ApplicationThread和AMS进行进程间通信,AMS以进程间通信的方式完成ActivityThread的请求后会回调ApplicationThread中的Binder方法,然后ApplicationThread会向H发送消息,H收到消息后会将ApplicationThread中的逻辑切换到ActivityThread中去执行,即切换到主线程中去执行。