Looper的代码非常少
成员变量
// 静态的ThreadLocal对象,
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
private static Looper sMainLooper; //Ui 线程的Looper对象
//消息队列
final MessageQueue mQueue;
//线程
final Thread mThread;
构造方法
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
构造方法 初始化消息队列,和当前的线程,记得MessageQueue的mQuitAllowed变量,如果为false代表该消息队列不能出队,而且只有Ui线程才能设置为false,这是因为下面的代码。
在ActivityThread中的main方法,调用这句代码。
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();
}
}
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));
}
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
而我们自己调用的方法
public static void prepare() {
prepare(true);
}
消息循环
这是关键方法
public static void loop() {
//获取当前Looper对象 因为是ThreadLocal中取出可以保证一个线程只有这么一个。
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
//当前的MessageQueue 消息队列,也保证了一个线程只有一个。
final MessageQueue queue = me.mQueue;
//确保这个线程是本地进程
Binder.clearCallingIdentity();
final long ident = Binder.clearCallingIdentity();
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
//如果msg为null,跳出死循环
return;
}
...
try {
//调用的就是handler的dispatchMessage(msg);
msg.target.dispatchMessage(msg);
}
...
//消息回收
msg.recycleUnchecked();
}
}
这段代码,先判当前的looper对象,接着获取到当前的MessageQueue,开启死循环。如果msg为null就跳出死循环,否则就调用handler的dispatchMessage(msg),在默认callBackweinull的情况下,就会把消息传给handler的handleMessage处理。
最后,消息回收到消息池中。
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
总结
我们看下Looper调用的典型代码
Looper.prepaer();
....
Looper.loop();
先通过prepaer()方法初始化,把Looper存入到ThreadLocal,上篇分析了ThreadLocal,可以知道它的作用,是确保一个线程对应一个ThreadLocalMap内部的Entry[]数组,而prepaer()方法又通过抛异常,确保了一个线程有且只有一个Looper对象,同样的该Looper对象也只有一个MessageQueue对象。
初始化完毕之后,接着调用loop()方法,开启死循环遍历MessageQueue里面的方法,同时通过MessageQueue的next()方法,同样是一个死循环,不停的查找msg,查找到就分发给Handler处理。
同时,主线程中的MessageQueue不能有出队操作,会一直运行阻塞着主线程,所以Looper.loop();调用的位置是main()方法的最后的位置。(当然如果能执行到下面,说明Looper出问题了,就会抛异常,结束程序)
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");