共计 18993 个字符,预计需要花费 48 分钟才能阅读完成。
开篇
核心源码
关键类
路径
Looper.java
frameworks/base/core/java/android/os/Looper.java
Message.java
frameworks/base/core/java/android/os/Message.java
MessageQueue.java
frameworks/base/core/java/android/os/MessageQueue.java
简述
在整个 Android 的源码世界里,有两大利剑,其一是 Binder 机制,另一个便是 Handler 消息机制。消息机制涉及 MessageQueue/Message/Looper/Handler 这 4 个类。
Handler 是 Android 中引入的一种让开发者参与处理线程中消息循环的机制。我们在使用 Handler 的时候与 Message 打交道最多,Message 是 Hanlder 机制向开发人员暴露出来的相关类,可以通过 Message 类完成大部分操作 Handler 的功能。
作为一名程序员,我们不仅需要知道怎么用 Handler,还要知道其内部如何实现的,这就是我写这篇文章的目的。
模型
消息机制(Handler)主要包含:
✨ Message:消息分为硬件产生的消息 (如按钮、触摸) 和软件生成的消息;✨ MessageQueue:消息队列的主要功能向消息池投递消息 (MessageQueue.enqueueMessage) 和取走消息池的消息 (MessageQueue.next);✨ Handler:消息辅助类,主要功能向消息池发送各种消息事件(Handler.sendMessage) 和处理相应消息事件(Handler.handleMessage);✨ Looper:不断循环执行(Looper.loop),按分发机制将消息分发给目标处理者。
实例
/*
* A typical example of the implementation of a Looper thread,
* using the separation of {@link #prepare} and {@link #loop} to create an
* initial Handler to communicate with the Looper.
*/
class LooperThread extends Thread {
public Handler mHandler;
public void run() {
Looper.prepare();
mHandler = new Handler() {
public void handleMessage(Message msg) {
// process incoming messages here
}
};
Looper.loop();
}
}
接下来我们就围绕这个实例展开讲解!
Looper
消息队列 MessageQueue 只是存储 Message 的地方,真正让消息队列循环起来的是 Looper,我们先来重点分析 Looper。
Looper 是用来使线程中的消息循环起来的。默认情况下当我们创建一个新的线程的时候,这个线程里面是没有消息队列 MessageQueue 的。为了能够让线程能够绑定一个消息队列,我们需要借助于 Looper:首先我们要调用 Looper 的 prepare() 方法,然后调用 Looper 的 Loop() 方法。
需要注意的是 Looper.prepare() 和 Looper.loop() 都是在新线程的 run 方法内调用的,这两个方法都是静态方法。
public static void prepare() {…}
private static void prepare(boolean quitAllowed) {…}
public static void loop() {…}
prepare()
我们来看一下 Looper.prepare(),该方法是让 Looper 做好准备,只有 Looper 准备好了之后才能调用 Looper.loop() 方法。
public static void prepare() {
prepare(true); // 无参,调用 prepare(boolean quitAllowed)
}
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
// 每个线程只允许执行一次该方法,第二次执行时已有 Looper,则会抛出异常!
throw new RuntimeException(“Only one Looper may be created per thread”);
}
// 创建 Looper 对象,并保存到当前线程的本地存储区
sThreadLocal.set(new Looper(quitAllowed));
}
上面的代码首先通过 sThreadLocal.get() 拿到线程 sThreadLocal 所绑定的 Looper 对象,由于初始情况下 sThreadLocal 并没有绑定 Looper,所以第一次调用 prepare 方法时,sThreadLocal.get() 返回 null,不会抛出异常。
ThreadLocal
ThreadLocal:线程本地存储区(Thread Local Storage,简称为 TLS),每个线程都有自己的私有的本地存储区域,不同线程之间彼此不能访问对方的 TLS 区域。
TLS 常用的操作方法:
set()
public void set(T value) {
Thread t = Thread.currentThread(); // 获取当前线程
ThreadLocalMap map = getMap(t); // 查找当前线程的本地储存区
if (map != null)
map.set(this, value); // 保存数据 value 到当前线程 this
else
createMap(t, value);
}
我们看下 getMap() 函数:
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
判断 map 是否为空,如果为空则创建 ThreadLocalMap:
void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
get()
public T get() {
Thread t = Thread.currentThread(); // 获取当前线程
ThreadLocalMap map = getMap(t); // 查找当前线程的本地储存区
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings(“unchecked”)
T result = (T)e.value;
return result;
}
}
return setInitialValue(); // 创建 ThreadLocalMap
}
查看 setInitialValue():
private T setInitialValue() {
T value = initialValue();
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
return value;
}
Looper 通过如下代码保存了对当前线程的引用:
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>(); // sThreadLocal 为 ThreadLocal 类型
所以在 Looper 对象中通过 sThreadLocal 就可以找到其绑定的线程。ThreadLocal 中有个 set 方法和 get 方法,可以通过 set 方法向 ThreadLocal 中存入一个对象,然后可以通过 get 方法取出存入的对象。
ThreadLocal 在 new 的时候使用了泛型,从上面的代码中我们可以看到此处的泛型类型是 Looper,也就是我们通过 ThreadLocal 的 set 和 get 方法只能写入和读取 Looper 对象类型。
构造函数
源码中 Looper 的构造函数是 private 的,也就是在该类的外部不能用 new Looper() 的形式得到一个 Looper 对象。
private Looper(boolean quitAllowed) {…}
我们看下上面代码中 new Looper() 创建 Looper 对象的工作:
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed); // 创建 MessageQueue 对象
mThread = Thread.currentThread(); // 记录当前线程
}
Looper.prepare()在每个线程只允许执行一次,该方法会创建 Looper 对象,Looper 的构造方法中会创建一个 MessageQueue 对象,再将 Looper 对象保存到当前线程 TLS。
prepareMainLooper()
另外,与 prepare() 相近功能的,还有一个 prepareMainLooper() 方法,该方法主要在 ActivityThread 类中使用。
public static void prepareMainLooper() {
prepare(false); // 设置不允许退出的 Looper
synchronized (Looper.class) {
// 将当前的 Looper 保存为主 Looper,每个线程只允许执行一次
if (sMainLooper != null) {
throw new IllegalStateException(“The main Looper has already been prepared.”);
}
sMainLooper = myLooper();
}
}
loop()
Looper.loop()的代码如下:
/**
* Run the message queue in this thread. Be sure to call
* {@link #quit()} to end the loop.
*/
public static void loop() {
final Looper me = myLooper(); // 获取当前线程绑定的 Looper 对象
if (me == null) {
throw new RuntimeException(“No Looper; Looper.prepare() wasn’t called on this thread.”);
}
final MessageQueue queue = me.mQueue; // 获取 Looper 对象中的消息队列
// Make sure the identity of this thread is that of the local process,
// and keep track of what that identity token actually is.
Binder.clearCallingIdentity();
// 确保在权限检查时基于本地进程,而不是基于最初调用进程
final long ident = Binder.clearCallingIdentity();
for (;;) {// 进入 loop 的主循环方法
Message msg = queue.next(); // might block(可能会堵塞)
if (msg == null) {// 没有消息,则退出循环
// No message indicates that the message queue is quitting.
return;
}
// This must be in a local variable, in case a UI event sets the logger
// 默认为 null,可通过 setMessageLogging() 方法来指定输出,用于 debug 功能
final Printer logging = me.mLogging;
if (logging != null) {
logging.println(“>>>>> Dispatching to ” + msg.target + ” ” +
msg.callback + “: ” + msg.what);
}
final long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs;
final long traceTag = me.mTraceTag;
if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
}
final long start = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
final long end;
try {
msg.target.dispatchMessage(msg); // 用于分发 Message
end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
if (slowDispatchThresholdMs > 0) {
final long time = end – start;
if (time > slowDispatchThresholdMs) {
Slog.w(TAG, “Dispatch took ” + time + “ms on ”
+ Thread.currentThread().getName() + “, h=” +
msg.target + ” cb=” + msg.callback + ” msg=” + msg.what);
}
}
if (logging != null) {
logging.println(“<<<<< Finished to ” + msg.target + ” ” + msg.callback);
}
// Make sure that during the course of dispatching the
// identity of the thread wasn’t corrupted.
final long newIdent = Binder.clearCallingIdentity(); // 确保分发过程中 identity 不会损坏
if (ident != newIdent) {
// 打印 identity 改变的 log,在分发消息过程中是不希望身份被改变的
}
msg.recycleUnchecked(); // 将 Message 放入消息池
}
}
我们接下来会重点分析 loop() 里面的几个函数:
myLooper()
前面我们说过,在执行完了 Looper.prepare() 之后,我们就可以在外部通过调用 Looper.myLooper() 获取当前线程绑定的 Looper 对象。
public static @Nullable Looper myLooper() {
return sThreadLocal.get(); // 还是通过 sThreadLocal.get()方法获取当前线程绑定的 Looper 对象
}
MessageQueue
// Looper 构造函数中创建了 mQueue,即 MessageQueue
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed); // 创建 MessageQueue 对象
mThread = Thread.currentThread(); // 记录当前线程
}
public static void loop() {
final Looper me = myLooper(); // 获取当前线程绑定的 Looper 对象
if (me == null) {
… …
}
final MessageQueue queue = me.mQueue; // 获取 Looper 对象中的消息队列
变量 me 是通过静态方法 myLooper() 获得的当前线程所绑定的 Looper,me.mQueue 就是当前线程所关联的消息队列。
for()
for (;;) {// 进入 loop 的主循环方法
我们发现 for 循环没有设置循环终止的条件,所以这个 for 循环是个死循环。
Message
Message msg = queue.next(); // might block
我们通过消息队列 MessageQueue 的 next 方法从消息队列中取出一条消息,如果此时消息队列中有 Message,那么 next 方法会立即返回该 Message,如果此时消息队列中没有 Message,那么 next 方法就会阻塞式地等待获取 Message。
dispatchMessage()
/*package*/ Handler target;
try {
msg.target.dispatchMessage(msg);
end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
msg 的 target 属性是 Handler,该代码的意思是让 Message 所关联的 Handler 通过 dispatchMessage 方法让 Handler 处理该 Message,关于 Handler 的 dispatchMessage 方法将会在下面详细介绍。
recycleUnchecked()
msg.recycleUnchecked(); // 分发后的 Message 回收到消息池,以便重复利用
小结
loop()进入循环模式,不断重复下面的操作,直到没有消息时退出循环:
1、读取 MessageQueue 的下一条 Message;
2、把 Message 分发给相应的 target;
3、再把分发后的 Message 回收到消息池,以便重复利用。
quit()
public void quit() {
mQueue.quit(false); // 消息移除
}
public void quitSafely() {
mQueue.quit(true); // 安全消息移除
}
Looper.quit() 方法的实现最终调用的是 MessageQueue.quit() 方法。
MessageQueue.quit()
void quit(boolean safe) {
if (!mQuitAllowed) {当 mQuitAllowed 为 false,表示不运行退出,强行调用 quit() 会抛出异常
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);
}
}
消息退出的方式:
当 safe = true 时,只移除尚未触发的所有消息,对于正在触发的消息并不移除
当 safe = flase 时,移除所有的消息
Handler
构造函数
无参构造
public Handler() {
this(null, false);
}
public Handler(Callback callback) {
this(callback, false);
}
public Handler(boolean async) {
this(null, async);
}
public Handler(Callback callback, boolean async) {
// 匿名类、内部类或本地类都必须申明为 static,否则会警告可能出现内存泄露
if (FIND_POTENTIAL_LEAKS) {// 默认为 false
final Class<? extends Handler> klass = getClass();
if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
(klass.getModifiers() & Modifier.STATIC) == 0) {
Log.w(TAG, “The following Handler class should be static or leaks might occur: ” +
klass.getCanonicalName());
}
}
// 必须先执行 Looper.prepare(),才能获取 Looper 对象,否则为 null
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; // 设置消息是否为异步处理方式
}
对于 Handler 的无参构造方法,默认采用当前线程 TLS 中的 Looper 对象,并且 callback 回调方法为 null,且消息为同步处理方式。只要执行的 Looper.prepare() 方法,那么便可以获取有效的 Looper 对象。
有参构造
public Handler(Looper looper) {
this(looper, null, false);
}
public Handler(Looper looper, Callback callback) {
this(looper, callback, false);
}
public Handler(Looper looper, Callback callback, boolean async) {
mLooper = looper;
mQueue = looper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
Handler 类在构造方法中,可指定 Looper,Callback 回调方法以及消息的处理方式(同步或异步),对于无参的 handler,默认是当前线程的 Looper。
dispatchMessage()
在 Looper.loop() 中,当发现有消息时,调用消息的目标 handler,执行 dispatchMessage() 方法来分发消息。
/**
* Handle system messages here.
*/
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
// 当 Message 存在回调方法,回调 msg.callback.run() 方法
handleCallback(msg);
} else {
if (mCallback != null) {
// 当 Handler 存在 Callback 成员变量时,回调方法 handleMessage()
if (mCallback.handleMessage(msg)) {
return;
}
}
// Handler 自身的回调方法 handleMessage()
handleMessage(msg);
}
}
我们需要重点分析下这个函数:
首先会判断 msg.callback 存不存在,msg.callback 是 Runnable 类型,如果 msg.callback 存在,那么说明该 Message 是通过执行 Handler 的 post() 系列方法将 Message 放入到消息队列中的,这种情况下会执行 handleCallback(msg)。
handleCallback
源码如下:
private static void handleCallback(Message message) {
message.callback.run();
}
这样我们就清楚地看到我们执行了 msg.callback 的 run 方法,也就是执行了 post() 所传递的 Runnable 对象的 run 方法。
mCallback
如果我们不是通过 post() 系列方法将 Message 放入到消息队列中的,那么 msg.callback 就是 null,代码继续往下执行。
接着我们会判断 Handler 的成员字段 mCallback 存不存在。mCallback 是 Hanlder.Callback 类型的,我们在上面提到过,在 Handler 的构造函数中我们可以传递 Hanlder.Callback 类型的对象,该对象需要实现 handleMessage 方法,如果我们在构造函数中传递了该 Callback 对象,那么我们就会让 Callback 的 handleMessage 方法来处理 Message。
final Callback mCallback;
public interface Callback {
/**
* @param msg A {@link android.os.Message Message} object
* @return True if no further handling is desired
*/
public boolean handleMessage(Message msg);
}
如果我们在构造函数中没有传入 Callback 类型的对象,那么 mCallback 就为 null,那么我们会调用 Handler 自身的 hanldeMessage 方法,该方法默认是个空方法,我们需要自己重写实现该方法。
/**
* Subclasses must implement this to receive messages.
*/
public void handleMessage(Message msg) {// 空函数
}
综上所述,我们可以看到 Handler 提供了三种途径处理 Message,而且处理有前后优先级之分:首先尝试让 post() 中传递的 Runnable 执行,其次尝试让 Handler 构造函数中传入的 Callback 的 handleMessage 方法处理,最后才是让 Handler 自身的 handleMessage 方法处理 Message。
Callback
Callback 是 Handle r 中的内部接口,需要实现其内部的 handleMessage 方法,Callback 代码如下:
public interface Callback {
public boolean handleMessage(Message msg);
}
Handler.Callback 是用来处理 Message 的一种手段,如果没有传递该参数,那么就应该重写 Handler 的 handleMessage 方法,也就是说为了使得 Handler 能够处理 Message,有两种办法:
向 Hanlder 的构造函数传入一个 Handler.Callback 对象,并实现 Handler.Callback 的 handleMessage 方法
无需向 Hanlder 的构造函数传入 Handler.Callback 对象,但是需要重写 Handler 本身的 handleMessage 方法
也就是说无论哪种方式,我们都得通过某种方式实现 handleMessage 方法,这点与 Java 中对 Thread 的设计有异曲同工之处。
在 Java 中,如果我们想使用多线程,有两种办法:
1. 向 Thread 的构造函数传入一个 Runnable 对象,并实现 Runnable 的 run 方法
2. 无需向 Thread 的构造函数传入 Runnable 对象,但是要重写 Thread 本身的 run 方法
所以只要用过多线程 Thread,应该就对 Hanlder 这种需要实现 handleMessage 的两种方式了然于心了。
在之前分析 Handler(用法篇)的时候我们讲到过两种重要的方法:sendMessage() 和 post(),我们从源码角度进行进一步分析!
sendMessage
我们看下 sendMessage() 源码处理流程:
public final boolean sendMessage(Message msg) {
return sendMessageDelayed(msg, 0);
}
sendMessageDelayed
public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis); // 最终调 sendMessageAtTime()
}
通过以上代码可以看书:sendMessage() 调用了 sendMessageDelayed(),sendMessageDelayed() 又调用了 sendMessageAtTime()。
Handler 中还有 sendEmptyMessage() 方法:
public final boolean sendEmptyMessage(int what)
{
return sendEmptyMessageDelayed(what, 0);
}
public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
Message msg = Message.obtain();
msg.what = what;
return sendMessageDelayed(msg, delayMillis);
}
public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis); // 最终还是要调 sendMessageAtTime()
}
由此可见所有的 sendMessage 方法和 sendEmptyMessage 最终都调用了 sendMessageAtTime 方法。
post
我们看下 post() 源码处理流程:
public final boolean post(Runnable r)
{
return sendMessageDelayed(getPostMessage(r), 0);
}
可以看到内部调用了 getPostMessage 方法,该方法传入一个 Runnable 对象,得到一个 Message 对象。
getPostMessage
getPostMessage() 的源码如下:
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}
通过上面的代码我们可以看到在 getPostMessage 方法中,我们创建了一个 Message 对象,并将传入的 Runnable 对象赋值给 Message 的 callback 成员字段,然后返回该 Message,然后在 post 方法中该携带有 Runnable 信息的 Message 传入到 sendMessageDelayed 方法中。由此我们可以看到所有的 post 方法内部都需要借助 sendMessage 方法来实现,所以 post() 与 sendMessage() 并不是对立关系,而是 post() 依赖 sendMessage(),所以 post() 方法可以通过 sendMessage() 方法向消息队列中传入消息,只不过通过 post() 方法向消息队列中传入的消息都携带有 Runnable 对象(Message.callback)。
sendMessageAtTime
通过分别分析 sendEmptyMessage()、post() 方法与 sendMessage() 方法之间的关系,我们可以看到在 Handler 中所有可以直接或间接向消息队列发送 Message 的方法最终都调用了 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
我们发现 sendMessageAtTime() 方法内部调用了 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 = this; // 将 Message 的 target 绑定为当前的 Handler
// 变量 queue 表示的是 Handler 所绑定的消息队列 MessageQueue,通过调用 queue.enqueueMessage(msg, uptimeMillis) 将 Message 放入到消息队列中。
queue.enqueueMessage(msg, uptimeMillis);
还记得我们之前在分析 Looper 的时候,最终提到的 dispatchMessage() 吗?我们回忆一下:
try {
msg.target.dispatchMessage(msg);
end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
MessageQueue
每个线程内部都维护了一个消息队列 —— MessageQueue。消息队列 MessageQueue,顾名思义,就是存放消息的队列。那队列中存储的消息是什么呢?
假设我们在 UI 界面上单击了某个按钮,而此时程序又恰好收到了某个广播事件,那我们如何处理这两件事呢?因为一个线程在某一时刻只能处理一件事情,不能同时处理多件事情,所以我们不能同时处理按钮的单击事件和广播事件,我们只能挨个对其进行处理,只要挨个处理就要有处理的先后顺序。
为此 Android 把 UI 界面上单击按钮的事件封装成了一个 Message,将其放入到 MessageQueue 里面去,即将单击按钮事件的 Message 入栈到消息队列中,然后再将广播事件的封装成以 Message,也将其入栈到消息队列中。
也就是说一个 Message 对象表示的是线程需要处理的一件事情,消息队列就是一堆需要处理的 Message 的池。线程 Thread 会依次取出消息队列中的消息,依次对其进行处理。
MessageQueue 中有两个比较重要的方法,一个是 enqueueMessage 方法,一个是 next 方法。enqueueMessage 方法用于将一个 Messag e 放入到消息队列 MessageQueue 中,next 方法是从消息队列 MessageQueue 中阻塞式地取出一个 Message。在 Android 中,消息队列负责管理着顶级程序对象(Activity、BroadcastReceiver 等)以及由其创建的所有窗口。
创建 MessageQueue
MessageQueue(boolean quitAllowed) {
mQuitAllowed = quitAllowed;
// 通过 native 方法初始化消息队列,其中 mPtr 是供 native 代码使用
mPtr = nativeInit();
}
next()
Message next() {
final long ptr = mPtr;
if (ptr == 0) {// 当消息循环已经退出,则直接返回
return null;
}
// 循环迭代的首次为 -1
int pendingIdleHandlerCount = -1; // -1 only during first iteration
int nextPollTimeoutMillis = 0;
for (;;) {
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();
}
// 阻塞操作,当等待 nextPollTimeoutMillis 时长,或者消息队列被唤醒,都会返回
nativePollOnce(ptr, nextPollTimeoutMillis);
synchronized (this) {
// Try to retrieve the next message. Return if found.
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;
if (msg != null && msg.target == null) {
// 当消息 Handler 为空时,查询 MessageQueue 中的下一条异步消息 msg,则退出循环
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
if (msg != null) {
if (now < msg.when) {
// 当异步消息触发时间大于当前时间,则设置下一次轮询的超时时长
nextPollTimeoutMillis = (int) Math.min(msg.when – now, Integer.MAX_VALUE);
} else {
// 获取一条消息,并返回
mBlocked = false;
if (prevMsg != null) {
prevMsg.next = msg.next;
} else {
mMessages = msg.next;
}
msg.next = null;
// 设置消息的使用状态,即 flags |= FLAG_IN_USE
msg.markInUse();
// 成功地获取 MessageQueue 中的下一条即将要执行的消息
return msg;
}
} else {
// 没有消息
nextPollTimeoutMillis = -1;
}
// 消息正在退出,返回 null
if (mQuitting) {
dispose();
return null;
}
// 当消息队列为空,或者是消息队列的第一个消息时
if (pendingIdleHandlerCount < 0
&& (mMessages == null || now < mMessages.when)) {
pendingIdleHandlerCount = mIdleHandlers.size();
}
if (pendingIdleHandlerCount <= 0) {
// 没有 idle handlers 需要运行,则循环并等待
mBlocked = true;
continue;
}
if (mPendingIdleHandlers == null) {
mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
}
mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
}
// 只有第一次循环时,会运行 idle handlers,执行完成后,重置 pendingIdleHandlerCount 为 0
for (int i = 0; i < pendingIdleHandlerCount; i++) {
final IdleHandler idler = mPendingIdleHandlers[i];
mPendingIdleHandlers[i] = null; // 去掉 handler 的引用
boolean keep = false;
try {
keep = idler.queueIdle(); // idle 时执行的方法
} catch (Throwable t) {
Log.wtf(TAG, “IdleHandler threw exception”, t);
}
if (!keep) {
synchronized (this) {
mIdleHandlers.remove(idler);
}
}
}
// 重置 idle handler 个数为 0,以保证不会再次重复运行
pendingIdleHandlerCount = 0;
// 当调用一个空闲 handler 时,一个新 message 能够被分发,因此无需等待可以直接查询 pending message
nextPollTimeoutMillis = 0;
}
}
nativePollOnce 是阻塞操作,其中 nextPollTimeoutMillis 代表下一个消息到来前,还需要等待的时长;当 nextPollTimeoutMillis = -1 时,表示消息队列中无消息,会一直等待下去。
当处于空闲时,往往会执行 IdleHandler 中的方法。当 nativePollOnce() 返回后,next() 从 mMessages 中提取一个消息。
enqueueMessage()
boolean enqueueMessage(Message msg, long when) {
// 每一个普通 Message 必须有一个 target
if (msg.target == null) {
throw new IllegalArgumentException(“Message must have a target.”);
}
if (msg.isInUse()) {
throw new IllegalStateException(msg + ” This message is already in use.”);
}
synchronized (this) {
// 正在退出时,回收 msg,加入到消息池
if (mQuitting) {
IllegalStateException e = new IllegalStateException(
msg.target + ” sending message to a Handler on a dead thread”);
Log.w(TAG, e.getMessage(), e);
msg.recycle();
return false;
}
msg.markInUse();
msg.when = when;
Message p = mMessages;
boolean needWake;
if (p == null || when == 0 || when < p.when) {
// p 为 null (代表 MessageQueue 没有消息)或者 msg 的触发时间是队列中最早的,则进入该该分支
msg.next = p;
mMessages = msg;
needWake = mBlocked; // 当阻塞时需要唤醒
} else {
// 将消息按时间顺序插入到 MessageQueue。一般地,不需要唤醒事件队列,除非
// 消息队头存在 barrier,并且同时 Message 是队列中最早的异步消息
needWake = mBlocked && p.target == null && msg.isAsynchronous();
Message prev;
for (;;) {
prev = p;
p = p.next;
if (p == null || when < p.when) {
break;
}
if (needWake && p.isAsynchronous()) {
needWake = false;
}
}
msg.next = p; // invariant: p == prev.next
prev.next = msg;
}
// 消息没有退出,我们认为此时 mPtr != 0
if (needWake) {
nativeWake(mPtr);
}
}
return true;
}
MessageQueue 是按照 Message 触发时间的先后顺序排列的,队头的消息是将要最早触发的消息。当有消息需要加入消息队列时,会从队列头开始遍历,直到找到消息应该插入的合适位置,以保证所有消息的时间顺序。
removeMessages()
void removeMessages(Handler h, int what, Object object) {
if (h == null) {
return;
}
synchronized (this) {
Message p = mMessages;
// 从消息队列的头部开始,移除所有符合条件的消息
while (p != null && p.target == h && p.what == what
&& (object == null || p.obj == object)) {
Message n = p.next;
mMessages = n;
p.recycleUnchecked();
p = n;
}
// 移除剩余的符合要求的消息
while (p != null) {
Message n = p.next;
if (n != null) {
if (n.target == h && n.what == what
&& (object == null || n.obj == object)) {
Message nn = n.next;
n.recycleUnchecked();
p.next = nn;
continue;
}
}
p = n;
}
}
}
这个移除消息的方法,采用了两个 while 循环,第一个循环是从队头开始,移除符合条件的消息,第二个循环是从头部移除完连续的满足条件的消息之后,再从队列后面继续查询是否有满足条件的消息需要被移除。
总结
最后用一张图,来表示整个消息机制:
图解:
✨ Handler 通过 sendMessage()发送 Message 到 MessageQueue 队列;✨ Looper 通过 loop(),不断提取出达到触发条件的 Message,并将 Message 交给 target 来处理;✨ 经过 dispatchMessage()后,交回给 Handler 的 handleMessage()来进行相应地处理。✨ 将 Message 加入 MessageQueue 时,处往管道写入字符,可以会唤醒 loop 线程;如果 MessageQueue 中没有 Message,并处于 Idle 状态,则会执行 IdelHandler 接口中的方法,往往用于做一些清理性地工作。
参考 Blog
01. https://blog.csdn.net/iisprin… 02. http://gityuan.com/2015/12/26…