Handler消息机制(Java层)
1.简介
Android应用程序是通过消息来驱动的,系统为每一个应用程序维护了一个消息队列,应用程序的主线程不断地从这个消息队列中获取消息,然后就对这些消息进行处理,这样就实现了通过消息来驱动应用程序的执行。
通过消息驱动的好处是,消息的发送方只要把消息放在应用程序的消息队列中就行了,而不需要等待消息的接收方处理完整个消息才返回,这样就可以提高系统的并发性。
各个元素的关系:
- Runnable和Message可以被压入某个MessageQueue中,形成一个集合。
- Looper循环地去做某件事情。
- Handler是“处理事情的地方”。
一句话概括他们是:
Looper不断获取MessageQueue中的一个Message,然后由Handler来处理。
就像中央处理器(Looper)不断从内存(MessageQueue)中读取指令(Message),执行指令(Handler),最终产生结果。
Looper负责创建一个MessageQueue,然后进入无限循环,不断从该MessageQueue中获取一个Message,将Message分发给对应的Handler处理。
Looper的主要作用:
- 与当前线程绑定,保证任何一个线程只有一个Looper实例,同时Looper也只有一个MessageQueue。
- Looper会不断从MessageQueue中去取消息,交给消息的target属性的dispatchMessage去处理。
与Windows应用程序的消息处理过程一样,Android应用程序的消息处理机制也是由消息循环、消息发送和消息处理这三部分组成。接下来将从源码的角度来分析这三个过程。
2.消息循环
在消息处理机制中,消息都是存放在一个消息队列中,而应用程序的主线程就是围绕这个消息队列进入一个无限循环的,直到应用程序退出。如果消息队列中有消息,应用程序的主线程就会把它取出来,并分发给相应的Handler进行处理;如果队列中没有消息,应用程序的主线程就会进入空闲等待状态,等待下一个消息的到来。消息的循环过程是有Looper类实现的,我们先看一下一个典型的Handler的用法:
class LooperThread extends Thread {
public Handler mHandler;
public void run() {
Looper.prepare();//Looper的准备工作
mHandler = new Handler() {//创建处理消息的Handler
public void handleMessage(Message msg) {
// process incoming messages here
}
};
Looper.loop();//消息循环
}
}
2.1 Looper.prepare()
首先从Looper.prepare()方法开始:
public static void prepare() {
prepare(true);
}
private static void prepare(boolean quitAllowed) {
//ThreadLocal变量是每个线程独有的,可以用来判断是否已经创建过Looper了,保证每个线程只有一个Looper对象
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
//将新创建的Looper对象保存在ThreadLocal变量中
sThreadLocal.set(new Looper(quitAllowed));
}
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);//创建一个消息队列,按照先进先出的原则进出
mThread = Thread.currentThread();//将当前线程保存在mThread变量中
}
可以看到,在Looper.prepare()方法中,创建了一个Looper对象,并将该Looper对象与当前线程进行关联了,保证一个线程只有一个Looper对象。同时在Looper中,创建了一个MessageQueue。这样的话,当前线程有一个Looper对象,Looper对象中又有一个MessageQueue。关系如下:currentThread->Looper->messageQueue。
MessageQueue的构造方法如下:
MessageQueue(boolean quitAllowed) {
mQuitAllowed = quitAllowed;
mPtr = nativeInit();//调用本地方法创建一个NativeMessageQueue
}
MessageQueue的初始化工作交由JNI方法nativeInit来实现了,它的主要工作是创建一个NativeMessageQueue,并把它保存在mPtr变量中。nativeInit方法的实现见Handler消息机制(Native)文章。
2.2 Handler的构建
接下来看Handler的创建:
//默认构造方法
public Handler() {
this(null, false);
}
/*
* Handler默认是同步的,除非async值为true。
* 异步消息代表中断或者事件,不需要与同步消息一起排队。
* 如果async为true,则handler会给每个Message或Runnable调用setAsynchronous(boolean)方法。
*/
public Handler(Callback callback, boolean async) {
....
//获取Looper对象,该Looper对象是当前线程关联的Looper对象ÿ