前言
本系列文章,将分享与Handler相关的知识,包括Handler的结构,运作流程,各个类的作用、之间的关系
内容提要
本篇文章将分析Looper的作用,以及主要的方法
重要属性
//线程局部变量,让每个线程存放自己的Looper
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
//主线程的Looper
private static Looper sMainLooper;
//消息队列
final MessageQueue mQueue;
//Looper对应的线程
final Thread mThread;
重要方法
private Looper(boolean quitAllowed)
Looper的构造方法
- 1.这是一个私有的构造方法,想真正构造一个Looper,需要用prepare系列方法
- 2.在这里就可以看到,消息队列由Looper创建,一个Looper,对应一个MessageQueue
- 3.这里获取了当前线程,那么可以想见,Android一定在主线程就创建了属于主线程的Looper
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
prepare系列方法
public static void prepare()
在当前线程创建一个Looper,如果需要为Handler自定义一个Looper,就需要调用这个。需要注意,在调用loop()方法之前,必须先调用prepare(),而当需要队列结束,则调用quit()
private static void prepare(boolean quitAllowed)
实际执行创建的方法
- 1.通过ThreadLocal,存放属于线程自己的Looper,既防止多个线程访问到同一个Looper,也防止同个线程创建多个Looper
- 2.队列是否允许退出,一经创建就不能更改
/** 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));
}
public static void prepareMainLooper()
创建MainLooper,应用程序会在初始化的时候自动为我们创建MainLooper,所以我们自己永远不需要调用它,只需要在要用的时候getMainLooper()即可
可以看到,mainLooper的创建,其实也是调用了prepare()方法,并且设置为不可退出,只是由于是在主线程创建的looper,并且在主线程调用了loop(),所以所有持有mainLooper的Handler,都得以在主线程执行handleMessage()
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
public static Looper getMainLooper() {
synchronized (Looper.class) {
return sMainLooper;
}
}
public static Looper myLooper() {
return sThreadLocal.get();
}
我们重新捋一下Looper线程切换的逻辑
- 1.应用程序在入口处(其实是在ActivityThread,有兴趣的可以去看一下源码)创建了一个不可退出的mainLooper,并且调用loop(),即是说,mainLooper在主线程不断地从MessageQueue取出到期的Message,执行handleMessage()回调
- 2.我们在任意子线程创建Handler,并传入mainLooper(Looper.getMainLooper()),由于mainLooper里面存放了MessageQueue,等于说这个Handler所发送的Message,都会被在主线程里取出,并回调。这样就达成了线程切换
- 3.总的来说,我们可以理解为,Handler这套机制,通过共享对象,达到了线程切换的目的
public static void loop()
Looper的核心方法
其实很简单,一个死循环,将Message出列,当队列为空时,结束循环
msg.target指的是Message持有的Handler
public static void loop() {
final Looper me = myLooper();
final MessageQueue queue = me.mQueue;
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
return;
}
msg.target.dispatchMessage(msg);
msg.recycleUnchecked();
}
}
public void quit()
退出loop(),MessageQueue会把所有Message出列
public void quit() {
mQueue.quit(false);
}
public void quitSafely()
退出loop(),一般来说,建议使用quitSafely(),MessageQueue会把所有未到期的Message出列,但是到期的会继续发送
public void quitSafely() {
mQueue.quit(true);
}
public static Looper getMainLooper()
获取主线程Looper
public static Looper getMainLooper() {
synchronized (Looper.class) {
return sMainLooper;
}
}
本篇内容到此结束,感谢收看~~
网友评论