本文介绍Android的消息机制。
一、引言
假设现在我们有这样的需求,点一下图中的button,然后去获取一些数据(假设这个步骤是一个耗时的操作),然后获取完后将得到的数据返回显示到屏幕上。
为了避免产生ANR(Application Not Response)问题,通常我们会在新的线程去做耗时的操作,然后在UI线程里面更新组件,所以Handler就是类似这样子一个机制。
那么我们会怎么去实现呢?可以参考如下:
1 | public class TestDriverActivity extends Activity { |
这只是一种实现的方式,如果在子线程而不是ui线程去初始化handler,则需要初始化handler前调用Looper.prepare(),初始化结束后调用Looper.loop()。
二、相关概念
学习Android的消息处理机制,有几个概念(类)必须了解:
- Message
消息,理解为线程间通讯的数据单元。例如后台线程在处理数据完毕后需要更新UI,则可发送一条包含更新信息的Message给UI线程。 - Message Queue
消息队列,用来存放通过Handler发布的消息,按照先进先出执行。 - Handler
Handler是Message的主要处理者,负责将Message添加到消息队列以及对消息队列中的Message进行处理。 - Looper
循环器,扮演Message Queue和Handler之间桥梁的角色,循环取出Message Queue里面的Message,并交付给相应的Handler进行处理。
Thread
5.UI thread 通常就是main thread,而Android启动程序时会替它建立一个Message Queue。
每一个线程里可含有一个Looper对象以及一个MessageQueue数据结构。在你的应用程序里,可以定义Handler的子类别来接收Looper所送出的消息。
三、Looper
Looper被设计用来使一个普通线程变成Looper线程。所谓Looper线程就是循环工作的线程。在程序开发中(尤其是GUI开发中),我们经常会需要一个线程不断循环,一旦有新任务则执行,执行完继续等待下一个任务,这就是Looper线程。使用Looper类创建Looper线程很简单:
1 | public class LooperThread extends Thread { |
3.1 Looper.prepare()
当执行了Looper.prepare()后,当前线程就会升级为Looper线程:
一个Thread只能有一个Looper对象
线程中有一个Looper对象,它的内部维护了一个消息队列MessageQueue
3.2 Looper.loop()
当调用loop方法后,Looper线程就开始真正工作了,它不断从自己的MQ中取出队头的消息(也叫任务)执行。
那么,我们如何往MQ上添加消息呢?下面有请Handler
四、Handler
Handler扮演了往MQ上添加消息和处理消息的角色(只处理由自己发出的消息),即往MQ上添加消息的时候执行sendMessage,并在loop到自己的时候处理消息执行handleMessage,整个过程是异步的。
Handler创建时会关联一个looper,默认关联当前线程的looper。
1 | public class LooperThread extends Thread { |
加入Handler后结构图如下:
一个线程可以有多个Handler,但是只能有一个Looper。
4.1 Handler发送消息和处理消息
大致流程:
mHandler.sendMessage()发送消息到MQ
Looper.loop()将message不断从MQ从取出来交给handler处理
mHandler.handleMessage()处理消息
五、回顾
那么回到一开始我们举的例子,在非UI线程去做耗时的操作,然后完成后在UI线程更新UI信息。那么这种case下,我们的结构图是这样的:
至此,本文介绍的内容已经完成,本文内容大部分非原创,更多的是基于其他博客的和自己理解的总结,好记性不如烂笔头。如果需要了解源码的同学,可以继续深入阅读研究,包括Java层Looper,Handler,Message,MessageQueue的源码和Native层Looper,NativeMessageQueue的源码实现。