写在前面
本节主讲Android消息循环机制中java 部分:Jave层的Looper,MessageQueue,Handler,涉及到native部分会先做简单解释跳过。后续会在第三节将jave与native 层串联起来。
涉及到的相关java的文件路径:
- Looper.java (android-5.1.0_r3\frameworks\base\core\java\android\os)
- MessageQueue.java (android-5.1.0_r3\frameworks\base\core\java\android\os)
- Message.java (android-5.1.0_r3\frameworks\base\core\java\android\os)
- Handler.java (android-5.1.0_r3\frameworks\base\core\java\android\os)
基本概念
- Looper :负责创建消息队列,并执行消息循环。
- MessageQueue :消息队列,消息以链表形式组织。Message不是直接加入到MessageQueue,而是通过一个与该looper绑定的handler添加进来的。
- Message :消息的格式。
- Handler:派发消息以及处理消息。
创建线程消息队列
主线程消息队列是在应用程序启动时,由framework层帮忙创建的,开发者无需关心。
而如果开发者希望自己创建的子线程也拥有消息循环机制,则需开发者自己去创建。
主线程消息队列的创建
消息队列是与Looper一对一绑定的,在Looper的构造函数中会创建MessageQueue。所以从Looper的构造函数开始。
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
Looper的构造函数是private的,因为每个线程中只能有一个looper,所以采用ThreadLocal来保存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
我们知道,系统启动应用程序的时候,就帮我们把主线程中的Looper创建好了,那是哪里创建的呢?
Android 创建应用程序的入口函数是ActivitThread.java 的main() 函数,在main() 函数中调用了Looper的静态方法prepareMainLooper(),将创建了Looper对象以及消息队列。
public static void main(String[] args) {
...
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
...
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
Looper . prepareMainLooper()
Looper.prepareMainLooper()函数中,会先透过prepare() 创建looper,如果发现之前已经创建过,存在重复创建的话,则会抛出异常,也就是一个线程中只能有一个looper对象的存在。所以Looper中会以ThreadLocal 来保存该对象。即为该变量在每个线程中提供独立的副本。
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
在prepare() 函数中,new 了一个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));
}
至此,主线程的Looper对象就创建好了,它是一个ThreadLocal变量, MessageQueue也创建好了。
子线程消息队列的创建
子线程如果需要消息循环机制的话,则需要开发者主动调用Looper.prepare()创建消息队列。
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
* {@l