Handler发送消息到MessageQueue中,Looper不断获取MessageQueue中的一个Message,然后分发给Handler去处理。这几个对象和线程的关系为:
那么根据以上关系,不难发现,一个消息要想得到处理,必须经过这几个步骤
接下来我们就看看这些步骤是怎样实现的
这要从两种情况考虑了,主线程和普通线程。我们先看看普通线程
先看一个使用Looper的典型样例代码:
class MyThread extends Thread{
private Handler mHandler;
@Override
public void run() {
Looper.prepare(); //初始化的工作在这里
mHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
// TODO: 处理消息
}
};
Looper.loop(); // 开始循环收发消息
}
}
Looper的prepare究竟做了什么呢?
public static void prepare() {
prepare(true);
}
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}
这里面有一个sThreadLocal的变量,它是一个static final 类型的ThreadLocal对象。它可以为每个线程提供资源的副本。我们可以看到 sThreadLocal.set(new Looper(quitAllowed)),也就是为每个线程提供了一个Looper对象。Looper中自带有一个MessageQueue的成员变量mQueue,在Looper的构造方法中被new了出来,这样,通过调用prepare系统就为每个线程创建了一个Looper对象并配套了一个MessageQueue。
UI主线程其实是一个名为ActivityThread类的实例,来看看它的入口程序吧
public static void main(String[] args) {
...
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
...
Looper.loop();
...
}
可以发现它和常规线程的不同之处,首先Looper的初始化方法改为了prepareMainLooper()。看看这个方法里面究竟做了什么
public static void prepareMainLooper(){
prepare(false);
synchronized(Looper.class){
if(sMainLooper != null){
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
它利用了上述的prepare方法生产了一个不许退出的Looper(因为传入的boolean为false),从本质角度来说这个Looper的其他线程的Looper并没有本质的区别。只是它被记录在了sMainLooper的成员变量里了,其他线程可以通过getMainLooper()方法得到它。但是其他的线程的Looper只能在线程内访问。主线程的非主线程的Looper的区别就在于两者的访问权限是不同的。
这个要看看Handler的构造器了,当查看了它的几个构造方法时,发现Handler的内部是有这几个成员变量的
final MessageQueue mQueue;
final Looper mLooper;
各个构造器的关键就在于为这两个成员赋值:
mLooper = Looper.myLooper(); //这里面就一句话 sThreadLocal.get(),也就是通过sThreadLocal来获得属于所在线程的Looper对象
...
mQueue = mLooper.mQueue; // 这样就绑定了Looper所管理的消息队列
也就是在new 一个Handler时,默认情况下就会绑定当前线程Looper的MessageQueue。当然Handler还有两个有参构造器,允许你在非主线程中绑定主线程的Looper。
我们在使用时会发现Handler可以发送两种类型的消息,一个是Message一个是Runnable。对于Runnable而言,最终也是被打包成Message中发送的。将会把Runnable赋值到Message的callback成员。看代码:
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}
...
public final boolean post(Runnable r){
return sendMessageDelayed(getPostMessage(r), 0);
}
打包成Message之后要怎样发送呢?,继续看代码
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
MessageQueue queue = mQueue;
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;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
在enqueueMessage中,msg.target被设置为this,也就是当前发送它的Handler,这个在未来分发和处理Message中我们会继续讨论。关键看看queue的enqueueMessage中是如何把Message插入的,我们看看它的关键部分
Message p = mMessages;
boolean needWake;
if (p == null || when == 0 || when < p.when) {
// New head, wake up the event queue if blocked.
msg.next = p;
mMessages = msg;
needWake = mBlocked;
} else {
// Inserted within the middle of the queue. Usually we don't have to wake
// up the event queue unless there is a barrier at the head of the queue
// and the message is the earliest asynchronous message in the queue.
needWake = mBlocked && p.target == null && msg.isAsynchronous();
Message prev;
for (;;) {
prev = p;
p = p.next;
if (p == null || when < p.when) {
break;
}
if (needWake && p.isAsynchronous()) {
needWake = false;
}
}
msg.next = p; // invariant: p == prev.next
prev.next = msg;
}
可见整个Queue非常想一种链表结构,首先看表头是不是为空,是的话就把msg放入,作为表头。否则就遍历整条链到最后一个消息,并把最新的消息插入。这样Handler就把Message发送到Queue中了
无论是否在主线程,都需要调用Looper的loop方法启动消息收发机制,看看loop都干嘛了
public static void loop(){
final Looper me = myLooper();
...
final MessageQueue queue = me.mQueue;
for(;;){
Message msg = queue.next();
if(msg == null){
return;
}
...
msg.target.dispatchMessage(msg);
...
msg.recycle();
}
}
首先通过myLooper()获取当前线程的Looper对象,再拿到对应的消息度列queue。然后遍历消息,注意取消息时可能因为没有消息可以拿到而阻塞。如果没有消息说明线程线程将要退出,故return了。还记得之前提过msg.target实际上个Handler吧,也就是发送它的那个Handler,开始对Message进行分发。最后回收这个处理过的Message。
关键看dispatchMessage方法,它的默认流程是这样的:
这就是Handler分发消息的原理——Handler负责收发,Looper负责不断的取消息,MessageQueue负责存储消息。还有很多细节笔者并没有写出,感兴趣的同学可以继续探讨。先就写这么多,如果所整理的有不当之处,欢迎读者批评指正。