续上篇
有关Handler你想要的都在这里了(一)
有关Handler你想要的都在这里了(二)
有关Handler你想要的都在这里了(三)
Handler、Looper、MessageQueue协同工作的示意图
读者应该对着流程图,看着我的帖子,跟着我的思路,翻着源码,去一步一步理解这个Handler机制的工作流程,不用妄想看一眼就懂,除非你原来就懂。
请带着脑子看帖子
下面我将尝试使用文字来描述这个工作的过程
一、我们使用Handler发送一个消息的时候,这个流程最终调用了MessageQueue的enqueueMessage()方法,这个方法的作用是将一个消息插入到消息队列中
那么我们不禁要问,MessageQueue是什么时候初始化的?
仔细看流程图中的sendMessageAtTime()方法
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);
}
仔细看这个方法中的第一行,就是将一个全局变量mQueue赋值给一个局部变量,然后再调用了enqueueMessage()方法,那么mQueue是什么时候赋值的呢?
聪明的人应该已经猜到了,就是构造方法中
public Handler(Callback callback, boolean async) {
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
*/
public Handler(Looper looper, Callback callback, boolean async) {
mLooper = looper;
mQueue = looper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
上面是Handler的两大类构造方法,源码我已经贴出来了,mQueue对象的初始化都是在构造方法中,具体来讲是在构造方法中从Looper中取的值,Looper的初始化我们先放下。
到这里我们再来回顾一下:
Handler中有一个成员变量mQueue,这个成员变量在Handler的构造方法中会初始化。
当我们发送一个消息的时候,这个消息最终通过调用了mQueue的enQueueMessage()方法,通过这个方法将一个消息存放到了消息队列中
Looper会通过loop()方法从消息队列中一条一条的取出消息,并且调用发送该消息的Handler的dispatchMessage()方法,从而这个消息就回到了发送该Message的Handler中
Handler的dispatchMessage()方法会调用自身的handleMessage()方法,handleMessage()方法就是我们处理消息的方法
到这里后,一条消息的发送—>处理流程就完成了。
我们再仔细看看Handler的空参的构造方法,这也是我们经常使用的方法。你也不要太懒,自己往下点着看看。
//空参的构造方法会调用这个构造方法
public Handler(Callback callback, boolean async) {
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
上面的构造方法第二行代码就是验证Looper是否为空,这就解释了我们在有关Handler你想要的都在这里了(一)第四部分怎么从主线程发送消息到子线程?(虽然这种应用场景很少)中的示例代码为什么要手动初始化一个Looper了,而且是要在Handler初始化之前初始化Looper
现在我们来看Looper的初始化
//Looper暴露出的静态初始化方法
//这个方法会调用下面的私有静态方法
public static void prepare() {
prepare(true);
}
//Looper私有的静态方法
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));
}
//私有的构造方法,禁止外界调用
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
解释一下上面三个方法
我们只能通过Looper.prepare()方法去初始化一个Looper
Looper.prepare(boolean)方法的逻辑是一个线程中只能有一个Looper对象,否则在第二次尝试初始化Looper的时候,就会抛出异常。
以线程为单位存储Looper的主要逻辑是通过ThreadLocal实现的
私有的构造方法,进制外界任意new出一个Looper
通过这段逻辑我们可以看出,一个线程中最多有一个Looper。
接着看Looper的构造方法,里面有一行代码
mQueue = new MessageQueue(quitAllowed);
是的,我们的MessageQueue是随着Looper的初始化而初始化的。那么,MessageQueue能不能随意的被new出来呢?
//MessageQueue的构造方法
MessageQueue(boolean quitAllowed) {
mQuitAllowed = quitAllowed;
mPtr = nativeInit();
}
可以看到,MessageQuede的构造方法是default的,也就是说,只有跟MessageQueue同一个包下才可以实例化MessageQueue,换句话说,我们用户是无法直接new一个MessageQueue对象出来的。而因为Looper在一个线程中只能有一个,从而导致MessageQueue也只能有一个。