Looper
稍微了解Handler的开发者,基本都知道Looper是干什么的,没猜错,就是为了循环获取消息队列里的消息,然后通过Handler的dispatchMessage()
方法里进行消息的处理。
初始化Looper
一般情况下进行对象的初始化,都是通过构造方法来进行初始化的
private Looper(boolean quitAllowed) {
//初始化一个消息队列
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
复制代码
源码可以看出,构造方法是private私有化的,所以不能直接在外部进行new来创建Looper对象;通过跟踪构造方法哪里进行调用了,可以看到prepare()方法里进行了调用。
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");
}
//创建一个Looper对象,并与当前线程进行绑定
sThreadLocal.set(new Looper(quitAllowed));
}
复制代码
代码很简单,就是先通过sThreadLocal进行获取,不为null直接抛出异常,为null直接创建一个Looper对象,并保存在sThreadLocal里边,关于ThreadLocal下篇文章我们再详细介绍,这里只做简单的说明就是
实现一个线程本地存储,是什么呢?一个让每个线程都有拥有value的变量。所有的线程都共享同个
ThreadLocal
对象,但每个线程在这拿到的value都不相同,并且一个线程在这里做的改变并不影响其他线程。支持值为null
。
这里可以引出一些常见的面试题
一个线程中可以多少个Looper对象
一个Looper对象可以有多少个消息队列
轮询消息队列loop()
这个没啥好说的,直接上源码,源码里的内容有些长,但是经过删减,最终的流程大致如下:
public static void loop() {
//首先拿到Looper对象
final Looper me = myLooper();
//如果Looper对象为空,直接抛出异常,
//调用loop方法前,必须在当前线程中先调用Looper.prepare()来生成Looper对象
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
//Looper的构造方法里创建的消息队列
final MessageQueue queue = me.mQueue;
//开启一个死循环
for (;;) {
//通过MessageQueue的next方法来从消息队列中取消息
Message msg = queue.next(); // might block
//如果取出的消息为空,则说明消息队列已经退出了,则结束死循环
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
//省略部分代码
.....
//交给msg.target即handler来处理该消息
msg.target.dispatchMessage(msg);
//最后将该消息进行回收
msg.recycleUnchecked();
}
}
复制代码
- 首先判断Looper对象是否为空,这里说明在当前线程调用
Looper.loop()
前,必须先调用Looper.prepare()
方法来创建一个Looper对象- 开启一个死循环,然后通过MessageQueue的
next()
方法来取出消息来,这里可以详细查看【Handler系列二】 MessageQueue,如果取出的消息为null,则说明当前消息队列已经终止,则直接退出死循环- 将取出的消息交给msg.target的
dispatchMessage()
方法进行处理,这里详细可以查看【Handler系列三】 Handler全解析 ,msg.target其实就是在Handler.obtainMessage()
的时候,将当前Handler赋值给该消息的- 最后将该消息进行回收
总结
Looper其实特别简单,就是提供一个死循环,然后从MessageQuene中获取消息,然后交给Handler来处理该消息,处理完成后,将该消息进行回收。
源码虽然简单,每次面试都会碰到关于Looper的面试题
- 一个线程可以有多个Looper对象,多少个消息队列,多少个Handler对象
- Looper在主线程开启死循环,为什么不会导致卡死
最后,欢迎各位读者留言来回答这两个面试题哦!!!
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END