前言
Android应用程序是基础Java语言,内部封装了消息队列,然后在主线程开启了死循环不断获取消息并处理来实现不间断的界面变化与各种操作的执行。这个过程主要由:Looper、Handler、Message三者来共同完成,Message作为消息载体,Looper用于封装消息队列,Handler用于插入与处理消息。
Looper简析
首先,看看Looper类的几个成员变量
// sThreadLocal.get() will return null unless you've called prepare().
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
private static Looper sMainLooper; // guarded by Looper.class
final MessageQueue mQueue;
final Thread mThread;
sThreadLoca并非是一个线程的实现版本,它并不是一个Thread,而是线程局部变量。简单地说,它是一种较为特殊的线程绑定机制。很显然,这里已经暴露了Looper与线程之间肯定有一些“特殊的联系”。
sMainLooper是个Looper对象,很显然Looper不可能是单例实现,并且从命名上我们也可以很容易看出来该对象,它可能是主线程/UI线程的Looper对象,咱们看到prepareMainLooper方法中初始化了这个对象
/**
* Initialize the current thread as a looper, marking it as an
* application's main looper. The main looper for your application
* is created by the Android environment, so you should never need
* to call this function yourself. See also: {@link #prepare()}
*/
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
从方法注释可以得知,该方法是实例化一个属于该应用主Looper(暂且这么理解),它是由系统自动调用,不需要你手动调用该方法
/**
* Returns the application's main looper, which lives in the main thread of the application.
*/
public static Looper getMainLooper() {
synchronized (Looper.class) {
return sMainLooper;
}
}
getMainLooper方法是提供获取主线程Looper对象,也就是说sMainLooper确实是属于主线程的Looper对象,并且它在应用开始时就被初始化了
具体的初始化位置于ActivityThread#main()方法中,有兴趣可自行了解
mQueue 是一个MessageQueue对象,咱们来看看官方对它的解释
/**
* Low-level class holding the list of messages to be dispatched by a
* {@link Looper}. Messages are not added directly to a MessageQueue,
* but rather through {@link Handler} objects associated with the Looper.
*
* <p>You can retrieve the MessageQueue for the current thread with
* {@link Looper#myQueue() Looper.myQueue()}.
*/
public final class MessageQueue {...}
我粗俗的翻译下,MessageQueue是一个低级类,通过Looper提供消息集合的派发,消息不会直接被添加到MessageQueue,而是通过Handler对象与其关联Looper对象。总结下,就是MessageQueue的作用只是简单是存储消息,具体的消息存取是由Handler与Looper来触发与管理。
之前咱们提到,Looper很可能与线程间存在密切联系。mThread成员变量再次证实了咱们的想法,怎么说?不急,咱们现在先分析下Looper中的核心方法
首先,prepare方法
/** Initialize the current thread as a looper.
* This gives you a chance to create handlers that then reference
* this looper, before actually starting the loop. Be sure to call
* {@link #loop()} after calling this method, and end it by calling
* {@link #quit()}.
*/
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));
}
初始化生成当前线程的Looper对象,只要当prepare方法执行了之后对应线程中才可以创建Handler对象,并且必须确保在loop执行前调用。从代码中可以看出来,此时sThreadLocal对象被实例化并与当前线程绑定,What?你是想说sThreadLocal.set(new Looper(quitAllowed));就完成了绑定?从哪得出线程信息了?好,我们再来看看构造器。