- 目录
- Handler、Looper、MessageQueue源码解析——Handler
- Handler、Looper、MessageQueue源码解析——Looper
- Handler、Looper、MessageQueue源码解析——ThreadLocal
- Handler、Looper、MessageQueue源码解析——MessageQueue
Looper
在Handler的构造函数中有这样一行代码:
mLooper = Looper.myLooper();
Looper是干什么的呢?
Looper负责创建一个MessageQueue,然后开启消息循环,不断的从MessageQueue取出消息,再交给Handler来处理消息。
Looper中两个最重要的方法是prepare()和loop(),我们分别来看看这两个方法的实现。
当我们要创建一个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");
}
sThreadLocal.set(new Looper(quitAllowed));
}```
sThreadLocal 是一个ThreadLocal对象,ThreadLocal以key-value的方式储存变量,并保证该变量线程间互不影响。prepare()方法在调用了set方法把一个new Looper对象存进去,所以可以看出prepare()方法只能调用一次,否则sThreadLocal不为空会抛出Exception。接下来进入到Looper的构造方法,一探究竟。
``` java
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
private static Looper sMainLooper; // guarded by Looper.class
final MessageQueue mQueue;
final Thread mThread;
...
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
在构造方法中新建的一个MessageQueue,并获取当前Thread对象。
在Handler构造方法中调用了Looper的myLooper()方法:
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
可以看出myLooper()方法通过ThreadLocal获取当前的线程的Looper对象,回到Handler的构造函数
public Handler(Callback callback, boolean async) {
...
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
...
}```
如果myLooper得到的Looper对象为空,则会抛出异常,也就是说在新线程我们如果要创建一个Handler必须要调用Looper.prepare()。那么,为什么我们在主线程不需要调用prepare()方法呢?
那是因为在ActivityThread中主线程的Looper已经开启:
public static void main(String[] args) {
...
Looper.prepareMainLooper();
...
}```
在Looper中:
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}```
所以在主线程再次调用prepareMainLooper()同样会报错。
再看Looper另外一个重要的方法,loop():
``` java
public static void loop() {
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue;
...
for (;;) {
// 从MessageQueue中不断取出消息
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
...
try {
//调用Handler的dispatchMessage (msg)方法
msg.target.dispatchMessage(msg);
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
...
msg.recycleUnchecked();
}
}```
可以看到,loop()方法是一个死循环,从MessageQueue中不断取出消息,然后调用handler的dispatchMessage(msg)方法,交给Handler来处理消息。直到消息队列为空才能结束循环,当然,我们也是可以手动结束消息循环的,Looper提供了两个方法:
public void quit() {
mQueue.quit(false);
}
public void quitSafely() {
mQueue.quit(true);
}```
调用MessageQueue的quit方法:
void quit(boolean safe) {
if (!mQuitAllowed) {
throw new IllegalStateException("Main thread not allowed to quit.");
}
synchronized (this) {
if (mQuitting) {
return;
}
mQuitting = true;
if (safe) {
removeAllFutureMessagesLocked();
} else {
removeAllMessagesLocked();
}
// We can assume mPtr != 0 because mQuitting was previously false.
nativeWake(mPtr);
}
}```
>当我们调用Looper的quit方法时,实际上执行了MessageQueue中的removeAllMessagesLocked方法,该方法的作用是把MessageQueue消息池中所有的消息全部清空,无论是延迟消息(延迟消息是指通过sendMessageDelayed或通过postDelayed等方法发送的需要延迟执行的消息)还是非延迟消息。
>当我们调用Looper的quitSafely方法时,实际上执行了MessageQueue中的removeAllFutureMessagesLocked方法,通过名字就可以看出,该方法只会清空MessageQueue消息池中所有的延迟消息,并将消息池中所有的非延迟消息派发出去让Handler去处理,quitSafely相比于quit方法安全之处在于清空消息之前会派发所有的非延迟消息。
具体实现我会在后面的MessageQueue中讲到。
以上就是Looper的大部分源码解析,读到这我们应该能大致知道Handler、Looper、MessageQueue消息处理机制大致是一个怎样的流程了。在Looper的源码中,我们遇到了一个新的东西——ThreadLocal,接下来我会带来ThreadLocal的源码分析。
网友评论