上一篇写了Handler的原理和简单使用,这一篇我们来看看Handler的源码。
先来看看Looper和MessageQueue的关系,以及主线程和子线程的Looper有何异同。
1、Looper和MessageQueue的关系
我们先从Handler的实现入手,先看看Handler(Looper)的实现,该方法实际调用了构造函数Handler(@NonNull Looper looper, @Nullable Callback callback, boolean async),源码如下:
public Handler(@NonNull Looper looper) {
this(looper, null, false);
}
public Handler(@NonNull Looper looper, @Nullable Callback callback, boolean async) {
mLooper = looper;
mQueue = looper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
从该构造函数的源码可以看到,参数looper不仅提供了Looper对象,还提供消息队列MessageQueue。所以异步消息机制中的消息队列MessageQueue是由Looper提供的。
2、主线程和子线程Looper的异同
再来看看不同线程Looper的获取:
//主线程
Looper mainLooper = Looper.getMainLooper()
//子线程
Looper.prepare()
Looper threadLooper = Looper.myLooper()
主线程的Looper可以直接获取,不需要显示初始化,子线程需要先调用Looper.prepare()初始化Looper。子线程Looper初始化的调用链如下:
//根据注释,必须先调用prepare()方法,才能调用Looper.loop()方法,结束后需要调用quit()退出
public static void prepare() {
prepare(true); //此处参数为true
}
private static void prepare(boolean quitAllowed) {
//当Looper已存在,抛出异常,一个线程只能有一个Looper
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}
//Looper构造方法
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
//MessageQueue构造方法
MessageQueue(boolean quitAllowed) {
mQuitAllowed = quitAllowed;
mPtr = nativeInit();
}
//mQuitAllowed唯一一处使用的地方
void quit(boolean safe) {
if (!mQuitAllowed) {
//抛出主线程不允许退出的异常
throw new IllegalStateException("Main thread not allowed to quit.");
}
synchronized (this) {
if (mQuitting) {
return;
}
mQuitting = true;
if (safe) {
removeAllFutureMessagesLocked();
} else {
removeAllMessagesLocked();
}
// We can assume mPtr != 0 because mQuitting was previously false.
nativeWake(mPtr);
}
}
顺着调用链可以看到,子线程Looper创建时调用了prepare(quitAllowed)方法,该方法调用构造函数Looper(quitAllowed),将创建的Looper存放进sThreadLocal。Looper(quitAllowed)构造方法内new了一个MessageQueue,传入boolean值为true的参数quitAllowed。参数quitAllowed如果为false,调用quit()会抛出异常,提示“主线程不允许退出”。该参数也和主线程有关,那我们再来看看主线程的Looper是如何初始化的,从Looper.getMainLooper()往上追溯:
public static Looper getMainLooper() {
synchronized (Looper.class) {
return sMainLooper;
}
}
//直接找到创建sMainLooper的方法;
//根据注释可知,该方法将初始化当前线程的Looper,并将该Looper标记为应用的主Looper
public static void prepareMainLooper() {
prepare(false); //此处参数是false
synchronized (Looper.class) {
//主线程同样只允许存在一个Looper
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
//定位到myLooper()方法
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
Looper.getMainLooper()调用了prepareMainLooper(),prepareMainLooper()也调用了prepare(quitAllowed)方法进行初始化。但传入的参数值是false。所以参数quitAllowed参数其实用来区分当前线程是否为子线程的 ,子线程中quitAllowed默认为true,当调用quit()可以直接退出。主线程中该方法为false,无法调用quit()结束loop()。
prepare(quitAllowed)将创建的Looper存放进sThreadLocal,prepareMainLooper()调用了myLooper()方法,该方法放回的是存放在sThreadLocal中的Looper。
所以主线程和子线程的Looper是没有差别的,只是主线程的Looper会默认初始化,且不能调用quit()直接退出loop()。
注意:
一个线程只能有一个Looper,一个Looper拥有一个MessageQueue;
主线程的Looper由系统初始化,子线程的Looper需要显示调用
Looper.prepare()初始化,且不能重复初始化。