Handler机制.源码分析
Posted 杨伟乔
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Handler机制.源码分析相关的知识,希望对你有一定的参考价值。
Handler机制的原理 :
android提供了handler 和 looper 来满足线程之间的通信
Handler是先进先出的原则
一个线程可以产生一个looper对象,由它去管理线程里面消息队列 MessageQueue
Handler 你可以构造handler对象来与looper沟通.可以发送消息 和处理消息
MessageQueue 用来存放线程放入的消息
线程 一般值的是主线程 UIthread
Android启动程序的时候会替他建立一个MessageQueue
.Handler创建消息
消息池
消息池
Handler发送消息
ThreadLocal
Handler 处理消息
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。
每一个消息都需要被指定的Handler处理,通过Handler创建消息便可以完成此功能。Android消息机制中引入了消息池。Handler创建 消息时首先查询消息池中是否有消息存在,如果有直接从消息池中取得,如果没有则重新初始化一个消息实例。使用消息池的好处是:消息不被使用时,并不作为垃
圾回收,而是放入消息池,可供下次Handler创建消息时使用。消息池提高了消息对象的复用,减少系统垃圾回收的次数。消息的创建流程如图所示。
2.Handler发送消息
UI主线程初始化第一个Handler时会通过ThreadLocal创建一个Looper,该Looper与UI主线程一一对应。使用
ThreadLocal的目的是保证每一个线程只创建唯一一个Looper。之后其他Handler初始化的时候直接获取第一个Handler创建的 Looper。Looper初始化的时候会创建一个消息队列MessageQueue。至此,主线程、消息循环、消息队列之间的关系是1:1:1。
Handler、Looper、MessageQueue的初始化流程如图所示:
Hander持有对UI主线程消息队列MessageQueue和消息循环Looper的引用,子线程可以通过Handler将消息发送到UI线程的消息队列MessageQueue中。
3.Handler处理消息
UI主线程通过Looper循环查询消息队列UI_MQ,当发现有消息存在时会将消息从消息队列中取出。首先分析消息,通过消息的参数判断该消息对应的Handler,然后将消息分发到指定的Handler进行处理。
子线程通过Handler、Looper与UI主线程通信的流程如图所示。
相关的术语 :
通信的同步 Synchronous指向客户端发送请求后,必须要在服务端有回应后客户端才继续发送其它的请求,所以这时所有请求将会在服务端得到同步,直到服务端返回请求。
通信的异步 Asynchronous 指客户端在发送请求后,不必等待服务端的回应就可以发送下一个请求。
所谓同步调用,就是在一个函数或方法调用时,没有得到结果之前,该调用就不返回,直到返回 结果。异步调用和同步是相对的,在一个异步调用发起后,被调用者立即返回给调用者,但是调用者不能立刻得到结果,被调用都在实际处理这个调用的请求完成 后,通过状态、通知或回调等方式来通知调用者请求处理的结果。
Android的消息处理有三个核心的类
Looper handler 和 message 其实还有一个MessageQueue 但是它被封装在looper中,不会直接和它打交道,所以不算是核心的类.
消息类Message类 主要的功能是进行消息的封装,同时可以指定消息的操作形式
Int whatobject obj Handler getTraget
尽管message有默认的构造,但是我们应该是通过Message.ontain() 来从消息池中获取消息对象,节省资源
如果是只是简单地携带int信息,优先使用Message.arg1和Message.arg2来传递信息,这比Bundle更省内存
善用message.what
来标示信息,以便不同的方式来处理message
消息通道 looper 系统会自动创建looper对象,但是如果是用户自定义的一个类中,就需要手动的调用looper中的方法.才可以启动looper对象
表面的意思是循环者,它被设计一个普通的线程变成looper线程,所说的looper线程就是循环工作的线程
.looper.prepare() ; 处理其他,比如实例化handler
…… looper.loop()
一个线程只可以有一个looper对象,为什么???
public
class Looper {
// 每个线程中的Looper对象其实是一个ThreadLocal,即线程本地存储(TLS)对象
private
static
final ThreadLocal sThreadLocal =
new ThreadLocal();
// Looper内的消息队列
final MessageQueue mQueue;
// 当前线程
Thread mThread;
//其他属性
// 每个Looper对象中有它的消息队列,和它所属的线程
private Looper() {
mQueue =
new MessageQueue();
mRun =
true;
mThread = Thread.currentThread();
}
// 我们调用该方法会在调用线程的TLS中创建Looper对象
public static final void prepare() {
if (sThreadLocal.get() !=
null) {
// 试图在有Looper的线程中再次创建Looper将抛出异常
throw
new RuntimeException(
"Only one Looper may be created per thread");
}
sThreadLocal.set(
new Looper());
}
// 其他方法
}
看源码 ,可以看出创建looper对象其实就是将looper对象定义为ThreadLocal,如果这个对象以前定义了,妮又尝试着去重新的定义,就是说threaLocal.get()!=null
这个时候对象存在,就会爆异常 .
looper.loop() 这个代表着启动looper 线程开始工作了.它不断的从队列里面取出消息.每次去的是第一个消息.源码分析 :
调用这个方法后,内部的执行流程
1.获取当前线程的looper对象Looper me = myLooper();这个方法内部其实就是返回 ThreadLocal.get()
2. 获取消息队列MessageQueue queue = me.mQueue;
3. 开启一个while死循环
用队列的对象取出下一个消息Message msg = queue.
next();
判断消息是否为空,如果是空,就不会继续执行了
如果不是空,将消息交给handlermsg.target.dispatchMessage(msg);
msg.recycle();回收msg资源
looper中的其他的方法 myLooper() getThread()
quit() 结束looper的循环
public void quit() {
// 创建一个空的message,它的target为NULL,表示结束循环消息
Message msg = Message.obtain();
// 发出消息
mQueue.enqueueMessage(msg,
0);
}
综上,Looper有以下几个要点:
1)每个线程有且只能有一个Looper对象,它是一个ThreadLocal
2)Looper内部有一个消息队列,loop()方法调用后线程开始不断从队列中取出消息执行
3)Looper使一个线程变成Looper线程。
那么,我们如何操作Message Queue上的消息呢?这就是Handler的用处了
消息操作类 handler
处理消息,但是很小气,只处理自己发出的消息
默认关联当前线程的looper
mLooper = Looper.myLooper();
判断looper是不是空的,如果是空的就爆异常,就是指handler只可以在looper线程中使用,
关联looper的消息队列,因为他的消息要发送到looper的消息队列中
public class LooperThread extends Thread {
private Handler handler1;
private Handler handler2;
@Override
public void run() {
// 将当前线程初始化为Looper线程
Looper.prepare();
// 实例化两个handler
handler1 = new Handler();
handler2 = new Handler();
// 开始循环处理消息队列
Looper.loop();
}
}
一个线程可以有多个handler 但是只能有一个looper
有了handler之后 就可以发送消息;了
post(Runnable)
postAtTime(Runnable, long)
postDelayed(Runnable, long)
sendEmptyMessage(int)
sendMessage(Message)
sendMessageAtTime(Message, long)
sendMessageDelayed(Message, long)
post发送消息最后都是把里面的Runnable封装成了message
// 此方法用于向关联的MQ上发送Runnable对象,它的run方法将在handler关联的looper线程中执行
Handler机制.源码分析