一、基本概念:
在谈到Android消息机制的时候,我们不可避免的要涉及要一下几个概念:
1、Message 消息
2、MessageQueue 消息队列
3、Handler 处理者?它的实际作用包括发送消息(sendMessage),处理消息(handleMessage)
4、Looper 消息循环,或者轮询器
从字面上来看,前两者都比较好理解。剩下的Handler、Looper,让我们先重点理解一下Looper:
二、Looper
Looper类的作用:
Class used to run a message loop for a thread. Threads by default do not have a message loop associated with them; to create one, call prepare() in the thread that is to run the loop, and then loop() to have it process messages until the loop is stopped.
简单翻译过来就是:Looper用于管理一个线程的消息循环。 默认情况下,线程是没有相关联的Looper的,需要调用Looper.prepare()来创建,创建完成之后,Looper.loop()会不断地循环来处理消息,直到循环停止。一般情况下是和Handler来配合使用的。
使用Looper+Handler典型代码例如:
class LooperThread extends Thread {
public Handler mHandler;
public void run() {
Looper.prepare(); //为本线程创建一个Looper
mHandler = new Handler() {
public void handleMessage(Message msg) {
// process incoming messages here
}
};
Looper.loop(); //消息循环
}
}
Looper重要属性:
// sThreadLocal.get() will return null unless you've called prepare()
static final ThreadLocal sThreadLocal = new ThreadLocal();
private static Looper sMainLooper; // guarded by Looper.class
final MessageQueue mQueue;
final Thread mThread;
其中,sThreadLocal是一个ThreadLocal对象,可以在一个线程中存储变量。
Looper的prepare()方法:
public static void prepare() {
prepare(true);
}
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) { //一个线程只能对应一个Looper实例
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed)); //new一个Looper的实例保存在ThreadLocal中
}
可以看到,prepare()方法将new一个Looper的实例,同时将该Looper实例放入了ThreadLocal。并且当第二次调用时报错,说明prepare()方法不能被调用两次,同时也保证了一个线程中只有一个Looper实例。
Looper的构造函数:
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
Looper构造函数中创建一个消息队列MessageQueue。同时也可以看到,一个Looper实例对应一个线程、一个MessageQueue
Looper的loop()方法:
public static void loop() {
// myLooper() 返回的是sThreadLocal.get(),也就是sThreadLocal存储的Looper实例
final Looper me = myLooper();
if (me == null) {
// 可以看到这里,如果在线程中没有调用Looper.prepare()的话Looper实例是空的
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue; //拿到Looper实例对应的消息队列
// Make sure the identity of this thread is that of the local process,
// and keep track of what that identity token actually is.
Binder.clearCallingIdentity();
final long ident = Binder.clearCallingIdentity();
for (;;) { //不断地从消息队列中取消息来进行处理
Message msg = queue.next(); // might block
if (msg == null) { // No message indicates that the message queue is quitting.
return;
}
... ...
msg.target.dispatchMessage(msg); //真正处理消息的地方
... ...
// Make sure that during the course of dispatching the
// identity of the thread wasn't corrupted.
final long newIdent = Binder.clearCallingIdentity();
if (ident != newIdent) {
Log.wtf(TAG, "Thread identity changed from 0x"
+ Long.toHexString(ident) + " to 0x"
+ Long.toHexString(newIdent) + " while dispatching to "
+ msg.target.getClass().getName() + " "
+ msg.callback + " what=" + msg.what);
}
msg.recycleUnchecked();
}
}
可以看到,方法中无限循环体里面,不断地通过queue.next()来取出准备处理的消息。而真正处理消息的地方是在这一句:msg.target.dispatchMessage(msg)。target是什么?我们可以从Message源码中可以看到,target是一个Handler,也就是说,真正处理消息是该消息对应的Handler实例的dispatchMessage(msg)方法中。
小结:
1、Looper用于管理一个线程的消息循环。
2、由于默认情况下,线程是没有相关联的Looper的,因此必须调用Looper.prepare()来创建。
3、Looper.prepare()方法,会使得线程绑定唯一一个Looper实例
4、Looper创建时也会创建一个消息队列MessageQueue。
2、Looper.loop()方法,不断从MessageQueue.next()中去取出准备处理的消息,交给消息的对应的handler的dispatchMessage去处理。
简言之,Looper提供了存储消息的队列(MessageQueue),同时不断循环取出准备处理的消息。那么谁来发送消息和真正处理消息呢?——当然是我们熟悉的Handler了。
三、Handler:
从第一部分我们可以推测出,Handler的两个重要作用:
1、发消息到MessageQueue中
2、接受Looper分发的消息处理任务,真正处理消息
那么Handler是怎么和一个线程的MessageQueue、Looper实例关联上的呢?
这个要看一下Handler是怎样被new出来的。具体我会另开文分析,这里以开篇的例子来分析,当使用new Handler()来创建一个Handler的情况(意思是还有其他情况):
public Handler() {
this(null, false);
}
最后是调用了这个:
public Handler(Callback callback, boolean async) {
if (FIND_POTENTIAL_LEAKS) {
final Class klass = getClass();
if ((klass.isAnonymousClass() || klass.isMemberClass()
|| klass.isLocalClass()) && (klass.getModifiers() & Modifier.STATIC) == 0) {
Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
klass.getCanonicalName());
}
}
mLooper = Looper.myLooper(); //这里,关联上了当前线程的Looper实例
if (mLooper == null) {
throw new RuntimeException(
// 在一个线程里面,创建handler之前必须调用Looper.prepare()
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue; // 这里,取得当前线程的Looper实例的消息队列
mCallback = callback;
mAsynchronous = async;
}
可以看到,在这种情况下,在构造函数里面,通过Looper.myLooper()获取了当前线程保存的Looper实例,然后又获取了这个Looper实例中保存的消息队列MessageQueue。Handler实例就是这样和一个线程的MessageQueue、Looper实例一一关联上的。
这里的当前线程,是指创建Handler实例所使用的线程。
接下来就简单了,用Handler发送一条消息,不论使用何种方法,最终都会调到这个函数:
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
MessageQueue queue = mQueue; //当前线程对应Looper实例的消息队列
if (queue == null) {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
return false;
}
return enqueueMessage(queue, msg, uptimeMillis);
}
然后调用了这个函数:
private boolean enqueueMessage(MessageQueue queue, Message msg,long uptimeMillis) {
msg.target =this; //将消息的target设为当前的Handler实例
if(mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis); //将消息插入到消息队列中去
}
重要的是这句:msg.target = this; //将消息的target设为当前的Handler实例
还记得第一部分结尾处,loop()方法中取出一条要处理的消息,然后调用msg.target.dispatchMessage(msg)嘛?那么现在我们知道了,msg的target就是在发这条消息的时候设置上的。以保证后续处理消息的时候,能找到处理这条消息的Handler。
queue.enqueueMessage(msg, uptimeMillis); //这句将设置好target等属性的消息放到消息队列中去
终于,让我们看一下msg.target.dispatchMessage(msg)的dispatchMessage()函数:
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
public void handleMessage(Message msg) {
}
这个方法最终调用我们在创建Handler时重写的handleMessage()方法或者callback来进行消息处理;
而handleMessage()我们就很熟悉了,每个创建Handler的都要重写handleMessage()方法,根据msg.what来处理消息,例如:
private Handler mHandler = newHandler() {
public void handleMessage(android.os.Message msg) {
switch(msg.what) {
case:
break;
default:
break;
}
};
};
三、总结
1、默认情况下线程是没有Looper实例的,Looper.prepare()为线程关联到唯一的Looper实例,以及Looper实例的MessageQueue。
2、Handler被创建时,会关联到“某个线程”的唯一的Looper实例和MessageQueue;Handler的主要作用是将处理消息切换到“这个线程”来处理。
3、当通过Handler发送一条Message时,该消息的target就被设为这个Handler实例(this)
4、Handler发送一条消息,实际上是将这条消息插入到对应的消息队列MessageQueue中
5、线程对应的Looper实例loop()方法来处理消息时,会根据这条消息的target(也就是Handler实例),回调Handler的dispatchMessage()方法进行处理。dispatchMessage()方法最终调用我们在创建Handler时重写的handleMessage()方法或者callback。
这里面,比较重要的是,明确Handler被创建时,和哪个线程或者和哪个线程的Looper相关联,这将决定了任务最后在哪个线程执行;
这里面有个特殊情况,就是在主线程创建Handler时不需要调用prepare()和loop(),因为这部分工作Android已经帮我们做过了,具体可以看一下ActivityThread的代码。
简单的说,一条消息从发出到处理经历了:
[Handler发送消息] -> [消息进入Looper的MessageQueue队列] -> [loop循环从MessageQueue取出要处理的消息] -> [Handler处理消息]
Reference:
Handler源代码
Looper源代码
Android 异步消息处理机制 让你深入理解 Looper、Handler、Message三者关系
Android异步消息处理机制完全解析,带你从源码的角度彻底理解
Android的消息机制之ThreadLocal的工作原理
Android中为什么主线程不会因为Looper.loop()里的死循环卡死?
Android异步消息处理机制详解及源码分析
Handler常见用法