Handler与Looper
文章目录
概述
先看一个Android中的HandlerThread
是如何使用Looper
的。
public class HandlerThread extends Thread {
@Override
public void run() {
......
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
......
Looper.loop();
......
}
public boolean quit() {
Looper looper = getLooper();
if (looper != null) {
looper.quit();
return true;
}
return false;
}
}
在线程的run
方法中调用Looper
的prepare()
方法进行准备工作,准备之后就可以通过Looper.myLooper
获取到当前的线程的Looper
了。使用然后调用loop
方法进入循环处理。使用的时候非常简单。接下来分析Looper
的实现。
而且可以quit
来退出线程,quit
方法中获取当前线程的looper
,不为null
会调用looper
对象quit
方法退出。
Looper
prepare方法
先分析一下静态的方法prepare
。
public final class Looper {
······
public static void prepare() {
prepare(true);
}
······
}
对外的静态方法prepare
调用私用的带有参数的prepare
方法。
public final class 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));
}
······
}
参数quitAllowed
标识是否允许looper退出。
首先调用sThreadLocal
参数获取是否有Looper
。
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
sThreadLocal
线程的本地对象,用于保存线程相关的变量。如果从sThreadLocal
获取Looper
对象不为null
,说明线程已经绑定了Looper,直接抛出异常。如果为从sThreadLocal
获取的Looper对象为null
,就创建一个Looper
,并设置到sThreadLocal
中。
public final class Looper {
······
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
······
}
Looper
的构造方法中创建MessageQueue
,用于保存消息处理。并保存当前的线程到mThread
变量中。
总结一下:
-
Looper.prepare()
会调用私有带有参数的prepare
方法 - 在私有的带有参数的
prepare
方法中会创建Looper
对象,并添加到线程的本地对象中。 -
Looper
的构造方法中会创建MessageQueue
消息队列对象。
loop方法
public final class Looper {
.......
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;
······
}
.......
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
......
}
loop
静态方法中,首先调用myLooper
获取当前的线程的looper
。如果为null
,说明线程未绑定Looper
,直接抛出异常。如果不为null
,获取Looper
中的消息队列MessageQueue
。
public final class Looper {
.......
public static void loop() {
······
for (;;) {
Message msg = queue.next(); // 消息队列为空,将一直阻塞
if (msg == null) {
return;
}
······
}
·····
}
}
接着是死循环,一直从消息队列中获取消息message
。当msg
为null
说明MessageQueue
正在退出,这里就直接从死循环中退出。接着分析。
public final class Looper {
public static void loop() {
for (;;) {
······
try {
msg.target.dispatchMessage(msg);
} finally {
}
······
}
······
}
}
消息对象的target
对象实际为Handler
对象。也就是调用了Handler
的dispatchMessage
对象来处理消息。
public final class Looper {
······
public static void loop() {
······
for (;;) {
······
msg.recycleUnchecked();
}
······
}
······
}
最后是调用msg
的recycleUnchecked
。也是就回收msg
,以备下次使用。
总结一下Looper.loop()
方法:
- 获取当前线程绑定的
Looper
的消息队列。 - 死循环中不断从消息队列中取出
Message
来处理。有消息就调用消息的target
(Handler
对象)的来处理。 - 最后回收
Message
。
quit方法
public final class Looper {
······
public void quit() {
mQueue.quit(false);
}
······
}
Looper
的quit
方法会调用消息队列的quit
方法。
分段阅读MessageQueue
的quit
方法。
public final class MessageQueue {
······
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();
}
······
}
}
······
}
MessageQueue
方法中先检测mQuitAllowed
用来判断是否支持退出,主线程的looper
是不支持的。
检测mQuitting
值来判断MessageQueue
是否已经退出了。如果mQuitting
为true
,说明MessageQueue
已经退出,就直接返回了。
如果mQuitting
是false
,接着执行,设置mQuitting = true,接着safe为true,说明是安全退出,会调用 removeAllFutureMessagesLocked()
。我们来分析一下removeAllFutureMessagesLocked()
private void removeAllFutureMessagesLocked() {
final long now = SystemClock.uptimeMillis();
Message p = mMessages;
if (p != null) {
//比较当前的message的执行的时间是否大于当前的时间。如果是就直接的移除所有的消息。
if (p.when > now) {
removeAllMessagesLocked();
} else {
Message n;
//循环比较获取时间点大于当前的时间点的消息。
for (;;) {
n = p.next;
if (n == null) {
return;
}
if (n.when > now) {
break;
}
p = n;
}
p.next = null;
//循环删除消息队列中时间点大于当前时间点的消息。
do {
p = n;
n = p.next;
p.recycleUnchecked();
} while (n != null);
}
}
}
此方法主要是根据删除执行的时间点大于当前时间点的消息。我接着分析MessageQueue
的quit
方法。
void quit(boolean safe) {
······
synchronized (this) {
······
if (safe) {
removeAllFutureMessagesLocked();
} else {
removeAllMessagesLocked();
}
nativeWake(mPtr);
}
}
如果safe
为false
,不是安全退出,直接调用removeAllMessagesLocked()
删除回收所有的Message
。
总结一下Looper
的quit
方法:
-
Looper
的quit
方法会调用消息队列MessageQueue
的quit
方法 -
MessageQueue
的quit
方法中,如果是非安全退出,直接移除所有的消息。如果是安全退出直接移除执行时间点大于当前时间点的Message
。
主线程中的Looper
主线程中的消息的管理也是通过Looper
来实现的。它与普通线程的Looper
不同的是有特殊的方法,但原理基本一致。
public final class Looper {
private static Looper sMainLooper; // guarded by Looper.class
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;
}
}
}
- 主线程的
Looper
有单独的变量sMainLooper
保存。 -
prepareMainLooper
方法用于准备主线的Looper
,它是在ActivityThread
的main
方法中调用的,也就是创建主线程时就会创建了。 -
getMainLooper
方法获取主线程的Looper
。
Handler
A Handler allows you to send and process Message and Runnable objects associated with a thread’s MessageQueue. Each Handler instance is associated with a single thread and that thread’s message queue.
从描述可以总结出Handler
一些特性:
- 每个
Handler
实例都会与一个线程以及线程的messageQueue
关联。 - 发送消息。
- 处理消息,处理
Runnable
。
Handler
与Looper
的关系图:
从上面的特性展开了三个问题:
- Handler是如何与线程的Looper关联的?
- Handler是如何发送消息的,发送到哪里了?
- Handler是如何处理消息的?
我们一个一个分析。
Handler与Looper关联
Handler
关联Looper
其实就是在构造方法中。以默认函数为例。
public class Handler {
public Handler() {
this(null, false);
}
/**
* @hide
*/
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()");
}
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
}
不传递任何参数将调用一个其他的构造方法。构造方法中直接获取Looper.myLooper()
来获取当前线程的Looper
,保存到mLooper
中,然后获取mLooper
的消息队列mQueue
保存到mQueue
中。保存Callback
用于处理消息。最后一个是mAsynchronous
,标识消息是否为异步处理。
这样就关联到了Looper
。
Hanlder处理消息
我们在Looper
的loop
方法中分析到,处理消息时回调用Message
的target
的dispatchMessage
方法处理,Message
的target
对象就是Handler
对象。
msg.target.dispatchMessage(msg);
那我们来分析dispatchMessage
来看看如何处理消息的。
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
private static void handleCallback(Message message) {
message.callback.run();
}
- 如果
msg
的callback
不为null
,就是直接调用callback
的run
方法。一般是通过post
方法发送的Runnable
。 - 然后判断
Handler
的mCallback
是否为null
,不为null
就调用mCallback
的handleMessage
的方法处理。 - 最后调用
Handler
的handleMessage
来执行。
Handler发送消息
发送消息通过两种方式:
-
post
相关的方法,来发送Runnable
。 -
sendMessage
相关的方法,发送一个Message
。
sendMessage方法
我们先来分析sendMessage
方法
public class Handler {
······
public final boolean sendMessage(Message msg)
{
return sendMessageDelayed(msg, 0);
}
······
}
此方法会调用sendMessageDelayed
方法,延迟的时间为0
。
public class Handler {
······
public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
······
}
此方法又会委托给sendMessageAtTime
来发送消息。
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
MessageQueue queue = mQueue;
if (queue == null) {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
return false;
}
return enqueueMessage(queue, msg, uptimeMillis);
}
此方法最后会调用enqueueMessage
来完成发送消息。
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
设置msg
的target
对象为当前对象,用于处理msg
。
并调用消息队列MessageQueue
的enqueueMessage
来添加到队列中去。
总结:
-
sendMessage
的方法最终会调用sendMessageAtTime
方法,然后调用enqueueMessage()
方法,而在enqueueMessage()
方法中会设置message.target
为此Handler
,这样Looper
获取到的Message
可以调用message.target
来处理了。
post方法
我们来分析post相关方法。
public class Handler {
······
public final boolean post(Runnable r)
{
return sendMessageDelayed(getPostMessage(r), 0);
}
······
}
post
方法显示通过getPostMessage
获取一个Message
。
public class Handler {
······
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}
······
}
然后通过sendMessageDelayed
发送消息。
总结:
-
post
方法实际上就是封装成Message
再发送。