andriod提供了Handler 和 Looper 来满足线程间的通信。Handler先进先出原则。Looper类用来管理特定线程内对象之间的消息交换(MessageExchange)。
1)Looper: 一个线程可以产生一个Looper对象,由它来管理此线程里的MessageQueue(消息队列)。
2)Handler: 你可以构造Handler对象来与Looper沟通,以便push新消息到MessageQueue里;或者接收Looper从Message Queue取出)所送来的消息。
3) Message Queue(消息队列):用来存放线程放入的消息。
4)线程:UIthread 通常就是main thread,而Android启动程序时会替它建立一个MessageQueue。
1. 使用场景
Android启动后,会创建一个进程,以后所有的activity、service都在这个进程里面运行。启动初,该进程只包含一个线程,叫做UI主线程,负责处理UI界面的显示、更新。对于一些费时的操作,如查询、下载数据等不可以放到UI线程中,因为这可能会引起UI线程阻塞,导致系统崩溃。所以,这些费时操作需要单独启动一个子线程去处理。子线程处理完毕将结果通知给UI主线程,主线程得到结果后更新UI界面。子线程如何与UI主线程进行通信?在android中使用了消息机制来完成线程之间的通信。
2. 场景分析
如何使用消息机制来解决上面的问题?假设UI线程有一个自己的消息队列,简称UI_MQ,UI_MQ用于存储UI线程需要处理的消息。子线程需要与UI线程通信时将消息发送到UI_MQ中即可。完成这些操作需要解决下面的问题:
(1) 为UI线程创建一个唯一的消息队列UI_MQ
(2) 子线程将消息发送到UI线程对应的消息队列UI_MQ
(3) UI线程循环查询UI_MQ是否有消息,如果有取出处理。
解决上面三个问题不难,对应的方法如下:
(1) 创建一个链表作为UI线程消息队列保存消息
(2) 子线程持有对UI_MQ的引用,便可以将消息加入到UI_MQ
(3) UI线程设置一个循环等待方法,用于处理UI_MQ。每当发现有消息存在,取出处理。
上面描述了消息推送的基本实现,如果设计一个好的消息通信框架,需要对此进一步完善,下面看android中的消息机制是怎么实现的。
3. 整体架构
Anroid中消息机制包括下面几个概念:对应的类图如图3.1所示。
(1) Thread 线程
(2) Message 消息
(3) MessageQueue 消息队列,每个线程里有唯一一个消息队列。
(4) MessagePool 消息池。
(5) Looper 循环查询消息队列,每个线程里有唯一一个消息循环。
(6) Handler 处理消息。作用有创建消息、发送消息、处理消息。
(7) ThreadLocal 保证每个线程只创建唯一一个Looper和MessageQueue。
“场景分析”提到,子线程持有UI线程消息队列UI_MQ的引用便可以将消息发送到UI_MQ中。Android中不是这么实现,android通过Handler创建消息、发送消息、处理消息。Handler是如何完成这些功能的呢?
Handler创建消息
每一个消息都需要被指定的Handler处理,通过Handler创建消息便可以完成此功能。Android消息机制中引入了消息池。Handler创建消息时首先查询消息池中是否有消息存在,如果有直接从消息池中取得,如果没有则重新初始化一个消息实例。使用消息池的好处是:消息不被使用时,并不作为垃圾回收,而是放入消息池,可供下次Handler创建消息时使用。消息池提高了消息对象的复用,减少系统垃圾回收的次数。消息的创建流程如图3.2所示。
Handler发送消息
UI主线程初始化第一个Handler时会通过ThreadLocal创建一个Looper,该Looper与UI主线程一一对应。使用ThreadLocal的目的是保证每一个线程只创建唯一一个Looper。之后其他Handler初始化的时候直接获取第一个Handler创建的Looper。Looper初始化的时候会创建一个消息队列MessageQueue。至此,主线程、消息循环、消息队列之间的关系是1:1:1。
Handler、Looper、MessageQueue的初始化流程如图3.3所示。
Hander持有对UI主线程消息队列UI_MQ和消息循环Looper的引用,子线程可以通过Handler将消息发送到UI线程的消息队列UI_MQ中。
Handler处理消息
UI主线程通过Looper循环查询消息队列UI_MQ,当发现有消息存在时会将消息从消息队列中取出。首先分析消息,通过消息的参数判断该消息对应的Handler,然后将消息分发到指定的Handler进行处理。
子线程通过Handler、Looper与UI主线程通信的流程如图3.4所示。
图 3.4 子线程通过Handler Looper与UI主线程进行通信