序言
随着科技的发展,人们的日常生活习惯也伴随着巨大改变。手机也取代了电脑,成为人们的“贴身小伙伴”,似乎时时刻刻都离不开手机,吃饭走路都要盯着手机,也造成了许多安全事故,希望大家在非必要时还是不要玩手机,利人利己啊。
说起智能手机系统,安卓系统当然是至今市场占有率最高的咯。谷歌也在不断优化系统,提升用户体验。作为安卓开发对于内部底层代码实现还是要熟知一二的,今天来详细讲解Handler消息传递机制。
Handler的主要工作就是为了满足UI线程和工作线程间(子线程)的通信,通常通信分为异步和同步:
异步通信:就好比有UI线程和子线程A,两个线程都需要执行任务,两者都准备就绪等待分配到CPU等资源去执行任务,我们无法控制任务完成的先后顺序。
同步通信:在UI线程和子线程B之间,某个时刻需要等到子线程B的任务执行完后,才可以再去开始UI线程的任务,这就是同步,保证了任务的执行顺序。
Android的消息处理机制中涉及到几个相关的类,最好能够熟悉其角色功能:
Handler Looper Message MessageQueue
下图简单的描述了相互间的通信流程:
可以看出Message对象就是数据的载体,装载着所要传递的信息。Handler将Message对象传给MessageQueue消息队列,Looper调用其loop方法将消息队列中的消息对象抽取出来然后给Handler处理。
Handler
Handler在整个消息处理流程的担当的职责还是挺多的,Handler就推动着整个流程的执行。首先将消息最终发送到消息队列(MessageQueue),消息队列会调用自己的enqueueMessage将消息添加到自己的队列中,后面由Looper的loop方法触发消息队列调用next方法取出队中的消息对象,然后通过Message的target变量(就是Handler)调用dispatchMessage方法对消息进行分发处理。后面会根据代码详细讲解整体流程。
Looper
Looper就相当于一个泵,不断去触发消息队列取出队列中的消息,Looper中的静态成员变量sThreadLocal(ThreadLocal<Looper>)存储着每个线程中的Looper对象,保证每个线程中Looper对象的唯一性,普通成员mQueue(MessageQueue)用来暂存消息对象,在每个线程中Looper和MessageQueue对象实例是唯一的,不可能在单个线程中出现多个Looper对象,否则会出错。
Message(消息类)
消息的载体,主要功能是对数据的封装,以便传递数据,下面讲解下其部分关联成员
1)public int what:定义不同的消息类型,可用于区分不同的业务
2)public int arg1:传递整型数据
3)public int arg2:传递整型数据
4)public Object obj:传递其他数据类型使用
5)Handler target:指向发送该消息的Handler对象
6)Runnable callback:用于指向Handler使用postxxx方法传递的Runnable对象,接口回调
MessageQueue(消息队列)
消息队列就是一个队列结构,暂存消息,保证消息对象先进先出
下面通过SDK-27的源码来详细讲解下整个流程:
既然Handler推动着整个流程的运转,那我们先从创建Handler对象切入:
//可以看到Handler对构造方法进行了多个重载
//默认与当前线程中的Looper关联,如没有Looper对象则抛出异常
public Handler() {
this(null, false);
}
//设置接口回调对象(执行的优先级低于message的callback,重载的handleMessage)
public Handler(Callback callback) {
this(callback, false);
}
//指定一个Looper对象与此关联
public Handler(Looper looper) {
this(looper, null, false);
}
//指定一个Looper对象与此关联,设置接口回调对象
public Handler(Looper looper, Callback callback) {
this(looper, callback, false);
}
//设置Handler是否异步
public Handler(boolean async) {
this(null, async);
}
//设置接口回调的Callback对象,并设置是否异步
public Handler(Callback callback, boolean async) {
if (FIND_POTENTIAL_LEAKS) {
final Class<? extends Handler> klass = getClass();
if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
(klass.getModifiers() & Modifier.STATIC) == 0) {