Handler异步通信机制网上的文章已经非常多了,看完文章都觉得好像理解,但一说又有些模糊,为了方便理解,决定用交互图的方式把整个过程画出来,会有一个更清晰的任务;画时序图使用在线Process On工具;
Handler机制时序图
Handler异步通信机制可以简单分解为几个阶段:
- 时序图中1-10步骤为新建Looper实例的阶段,关联消息队列MessageQueue;
- 时序图中11-18步骤为将Looper实例与所属线程绑定,Thread线程下私有threadLocals(ThreadLocal#ThreadLocalMap类型,类似Map存储方式)变量以ThreadLocal为key,Looper实例做value存储;
- 时序图中19-31步骤为完成Handler和线程绑定的Looper、MessageQueue建立关联关系;
- 时序图中32-34步骤为获取消息Message载体,Message的target为当前所属的Handler,即指定Message最终发给那个Handler处理器处理;
- 时序图中35-37步骤为将Message消息载体调用MessageQueue的enqueueMessage(message)加入消息队列;
- 时序图中38-44步骤为Looper调用loop()方法开发MessageQueue消息队列读取,然后获取Message,通过Message的target派发给相应的Handler处理;
- 时序图中44-45步骤为MessageQueue消息队列退出,主线程不允许退出消息队列,非主线程可以退出消息队列;
1.Handler,Message,MessageQueue,Looper类之间关系
Handler,Message,MessageQueue,Looper依赖关系;
- Handler是针对开发人员使用,负责发送消息Message到消息队列,消息Message的处理;Handler持有Looper和MessageQueue,Handler实际持有的Looper实例下的MessageQueue对象;Handler发送消息Message时最终调用MessageQueue.enqueueMessage(Message,long)方法将消息加入消息队列;派发消息基于Message指定的target(Handler).dispatchMessage(msg);处理消息基于Handler.handleMessage()处理;
- Looper实现消息的循环调用,Looper内部实现了Looper实例和所属线程的绑定,同时创建MessageQueue队列实例,Looper提供loop()方法实现读取消息死循环,MessageQueue.next()返回Message,调用Message.target.dispatchMessage(msg)派发消息;
- MessageQueue存放Message消息单链表,提供对Message操作方法,添加消息队列,读取消息,退出消息队列等;
- Message消息载体,携带了信息和处理Message的Handler,what参数用于区分动作类型,when代表执行时间点,target目标Handler即由哪个处理器处理Message,next单链表存储Message,arg1、arg2、obj、data四个参数主要用于存储传递信息,其他参数参考Message源码即可;尽管Message有public的默认构造方法,但是你应该通过Message.obtain()或者Handler.obtainMessage()来从消息池中获得空消息对象,以节省资源。
注意:主线程(即UI线程)启动时,Looper同时会创建一个实例,同时与主线程绑定,一个线程对应一个Looper实例,Looper构造函数同时会创建一个消息队列MessageQueue,一个Looper实例对应一个MessageQueue实例,MessageQueue采用单链表(先进先出)的方式存储Message,Handler在构造函数中通过Looper.myLooper()获取所属线程绑定的Looper和MessageQueue,MessageQueue不对外开放;
自定义Looper线程示例:
* <pre>
* class LooperThread extends Thread {
* public Handler mHandler;
*
* public void run() {
* Looper.prepare();
*
* mHandler = new Handler() {
* public void handleMessage(Message msg) {
* // process incoming messages here
* }
* };
*
* Looper.loop();
* }
* }</pre>