安卓中Handler框架处理消息,其中Looper类用来循环从MessageQueue类中获取消息,然后调用Handler进行消费.本文将基于安卓9.0代码带分析Looper的实现.
Looper类比较简单,其主要类成员变量比较少.
static final ThreadLocal sThreadLocal = new ThreadLocal();
存放Looper的线程共享变量,每个线程的Looper是不同的.
final MessageQueue mQueue;
消息队列
final Thread mThread;
Looper绑定的线程
private static Looper sMainLooper;
主线程Looper
//构造方法是私有的,一般会有静态方法来常见实例.
private Looper(boolean quitAllowed) {
//创建消息队列.
mQueue = new MessageQueue(quitAllowed);
//保存创建Looper的当前线程实例.
mThread = Thread.currentThread();
}
在Looper中构造方法中,首先创建了消息队列MessageQueue实例保存到了成员变量mQueue中,其次将当前线程实例存放到mThead成员变量中,完成Looper和线程的绑定.
该构造方法有一个参数:quitAllowed,表示该Looper是否可以提出,通过后面的代码分析可以看到主线程的Looper是不认不能退出的,其他线程的Looper是可以退出的.
Looper只有一个私有的构造方法,所以不允许直接通过new方法创建一个Looper实例,需要通过Looper的提供的静态工厂方法创建实例.
Looper类中提供了三个静态工厂方法, 创建Looper实例.
//创建Looper.
private static void prepare(boolean quitAllowed) {
//创建前先从本地线程变量sThreadLocal中获取Looper,如果取到就抛出异常,不能重复创建.
//所以创建
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
//直接newLooper的实例,并将Looper保存到本地变量中.
sThreadLocal.set(new Looper(quitAllowed));
}
在该方法中创建Looper实例,在创建以前调用sThreadLocal.get()
获取当前线程的Looper,如果获取到就抛出异常"Only one Looper may be created per thread"
,该异常说明一个线程只能创建一个Looper,不能重复创建.
sThreadLocal.set(new Looper(quitAllowed));
表明将创建的looper实例保存到sThreadLocal中,从而保证每个线程的Looper不被覆盖.
//主线程的Looper不能退出的,只能创建一次,并且创建后保存到
public static void prepareMainLooper() {
//直接调用perpare方法创建,传入参数false,表示不能退出.
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
//将主线程的Looper的保存到静态成员变量sMainLooper,方便在其他线程中获取主线程的Looper.
sMainLooper = myLooper();
}
}
创建主线程Looper的时候调用prepare(false);
创建,传入的参数为false,说明不能退出.将创建好的Looper实例保存到sMainLooper成员变量中.
在Android的实际开发工作中,我们不会去调用prepareMainLooper()方法来创建Looper实例,因为App在一启动的时候就自动创建了Looper实例
public final class ActivityThread extends ClientTransactionHandler {
...
public static void main(String[] args) {
...
//创建主线程Looper.
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false, startSeq);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
//启动Looper的死循环
Looper.loop();
}
}
//子线程的创建的Looper都是可以退出的.
public static void prepare() {
prepare(true);
}
通过调用prepare(true)
方法在子线程中创建Looper实例,参数为true,表明子线程创建的Looper可以退出的.
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
通过myLooper()方法,在线程本地变量中获取Looper.
在主线程中,直接调用Looper.myLooper()方法返回的就是主线程的Looper.
在其他线程中,需要使用Looper.getMainLooper()方法获取主线程的Looper.
所以一直建议使用Looper.getMainLooper()方法获取主进程的Looper.
public static Looper getMainLooper() {
synchronized (Looper.class) {
return sMainLooper;
}
}
下面是loop()代码,删掉大量和核心逻辑无关的代码.
public static void loop() {
//首先获取当前的Looper,如果不存在,就抛出异常.
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
//获取当前Looper关联的MessageQueue
final MessageQueue queue = me.mQueue;
//创建死循环获取消息.
for (;;) {
//获取下一条消息.
Message msg = queue.next(); // might block
//如果消息为null,就跳出循环,提出Looper.
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
...
//调用Handler的dispatchMessage方法处理消息.
try {
msg.target.dispatchMessage(msg);
} finally {
}
...
msg.recycleUnchecked();
}
}
Looper创建了一个死循环,从mQueue获取消息,获取到后调用Handler进行处理,如果获取的消息为null就退出Looper.
Looper类提供了两个方法quit()和quitSafely()来退出Looper,通过方法名字就可以看出一个安全退出的,一个是非安全退出.
public void quit() {
mQueue.quit(false);
}
调用该方法后,直接终止Looper,不处理任何的message.
public void quitSafely() {
mQueue.quit(true);
}
调用该方法可以安全退出Looper,它处理完所有的消息后在终止,调用该方法后不能在把Messag放到消息队列中.