Android的消息机制是由Handler+MessageQueue+Looper三个成为整体共同协作的工作过程。其中Handler可将一个任务切换到指定的线程中去。
在日常开发中,我们都知道系统规定我们必须在主线程(UI线程)中去操作UI控件,同时不建议我们在主线程中执行耗时的操作。
为什么不能在子线程中更新UI呢?因为UI控件是不安全的,但是如果用锁的机制又会影响访问的效率和逻辑变得复杂。ViewRootImpl对UI操作做了验证,验证的方法是checkThread来完成的。
消息的发送:
Looper发现有新的消息时,到最后会调用Runable或者Handler的handlerMessage方法
其中Looper是运行在创建Handler所在的进程中
ThreadLocal:是一个线程内部的数据储存类,他可以把数据储存到指定的线程中去,然后
在指定的线程才能获取保存在该线程中的数据,其他线程访问不到这些数据。
在Looper、ActivityThread的、AMS都用到了ThreadLocal。
ThreadLocal用法:它可以指定要操作的类型,在不同线程中设置不同的值。
set方法
1.获取当前线程
2.根据当前线程获取Values(内部类)对像
3.将ThreadLocal的值储存到table(Object[])数组中去
4.将ThreadLocal的引用储存在table[index]中
5.将ThreadLocal的value保存在table[index+1]中
get方法
1.获取当前线程
2.根据当前线程获取指定的Values对象
3.找到ThreadLocal中引用对象在table中的位置,然后在下一个位置找到ThreadLocal的值
消息队列在Android中指的是MessageQueue:
Looper在Android的消息机制中扮演着消息循环的角色,不停地从MessageQueue中查看是否有新消息
在Looper在构造方法中它会创建一个MessageQueue,并将当前的线程保存起来
通过Looper.prepar()即可创建一个Looper,接着通过Looper.loop()来开启消息循环
Looper中的PrepareMainLooper方法,主要是给主线程使用的,它的本质也是prepare方法来实现的,
Looper还提供一个getMainLooper方法来获取主线程的Looper。
退出Looper:
quitSafely方法:设定一个退出标记,然后把消息队列中的消息处理完之后再安全退出
建议在不需要的时候终止Looper
loop方法:里面是一个死循环,唯一能够跳出来的条件是MessageQueue的next方法返回null。 当调用 Looper的quit方法时,MessageQueue的quit或者quitSafely方法来通知消息队列退出,当消息队列被标记为退出状态时,它的next方法会返回null。
在源码中:其中有msg.target,这是一个Handler,它调用dispatchMessage方法,即将消息交由这个方法处理。
Handler发送消息:仅仅是向消息队列插入一条消息,MessageQueue的next方法将消息传给Looper,Looper将收到的消息进行处理,然后交由Handler(dispatchMessage方法)。
Handler处理消息的过程:
Handler的特殊构造方法:this(looper,null,false),这就说明了如果当前线程没有Looper的话,则会抛出异常
Activity的主线程就是ActivityThread,入口为main方法
main方法里面通过Looper.preparMainLooper来创建主线程的Looper和MessageQueue,然后调用Looper.loop方法进行主线程的消息循环
ActivityThead.H是一个Handler,内部定义了一组消息类型,主要包含四大组件的启动和停止
ActivityThread通过ApplicationThread和AMS进行进程间的通信
AMS->回调ApplicationThread中的Binder方法->ApplicationThread向H发送消息->H将逻辑切换到ActivityThread中执行