先看一个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方法退出。
先分析一下静态的方法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.loop()方法:
-获取当前线程绑定的Looper的消息队列。
-死循环中不断从消息队列中取出Message来处理。有消息就调用消息的target(Handler对象)的来处理。
-最后回收Message。
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不同的是有特殊的方法,但原理基本一致。
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。
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一些特性:
1.每个Handler实例都会与一个线程以及线程的messageQueue关联。
2.发送消息。
3.处理消息,处理Runnable。
Handler与Looper的关系图:
从上面的特性展开了三个问题:
1.Handler是如何与线程的Looper关联的?
2.Handler是如何发送消息的,发送到哪里了?
3.Handler是如何处理消息的?
我们一个一个分析。
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。
我们在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来执行。
发送消息通过两种方式:
-post相关的方法,来发送Runnable。
-sendMessage相关的方法,发送一个Message。
我们先来分析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相关方法。
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再发送。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。