Android 消息机制深入源码分析 [ 一 ]
Android 消息机制之 ThreadLocal 深入源码分析 [ 二 ]
Android 消息机制之 Looper 深入源码分析 [ 三 ]
Android 消息机制之 Message 与消息对象池的深入源码分析 [ 四 ]
Android 消息机制之 MessageQueue 深入源码分析 [ 五 ]
Android 消息机制之初识Handler [ 六 ]
Android 消息机制之 Handler 发送消息的深入源码分析 [ 七 ]
Android 消息机制之 MessageQueue.next() 消息取出的深入源码分析 [ 八 ]
Android 消息机制之消息的其他处理深入源码分析 [ 九 ]
Android 消息机制总结 [ 十 ]
上一章分析学习了消息机制中重要的取出操作, 本章对剩余消息分发处理, 移除, 查看消息是否存在等的分析.
先来看消息的分发处理.
1. Handler.dispatchMessage(Message msg)
在 Looper.loop()
方法内调用. 先从 MessageQueue
中获取到一个消息后, 再调用这个方法传入获取的消息进行分发处理.
Handler.java 97 行.
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
//当 Message 存在回调方法, 回调 msg.callback.run() 方法
handleCallback(msg);
} else {
if (mCallback != null) {
//当创建 Handler 时, 传入的参数为 Callback 的时候, , 回调方法为 Handler.Callback.handleMessage()
//在第六篇中有分析到这个 Callback.
//如果我们实现的 Callback 接口中 handleMessage 返回 true, 则表示不会调用 Handler 自身的 HandleMessage() 方法.
if (mCallback.handleMessage(msg)) {
return;
}
}
//Handler 自身的回调方法 handlerMessage()
handleMessage(msg);
}
}
在分发消息三个方法啊的优先级
-
Message
的回调方法优先级最高. 既message.callback.run()
-
Handler
的回调方法次之, 既Handler.Callback.handleMessage
-
Handler
的默认方法优先级最低.
很多情况下, 消息分发后的处理都是第三种情况, 一般往往都是通过复写第三种方法, 从而实现自己的业务逻辑.
2. 消息的移除
消息的移除其实就是根据身份 what / Runnable / msg.obj
移除队列中对应的消息, 例如发送消息时, 用同一个 msg.what
作为参数, 所有方法最终调用 MessageQueue.removeMessages
来操作.
调用方法的入口依然是在 Handler.java 中
public final void removeCallbacks(Runnable r) {
mQueue.removeMessages(this, r, null);
}
public final void removeCallbacks(Runnable r, Object token) {
mQueue.removeMessages(this, r, token);
}
public final void removeMessages(int what) {
mQueue.removeMessages(this, what, null);
}
public final void removeMessages(int what, Object object) {
mQueue.removeMessages(this, what, object);
}
public final void removeCallbacksAndMessages(Object token) {
mQueue.removeCallbacksAndMessages(this, token);
}
不难看出 Handler
中的删除工作, 其实都是通过调用 MessageQueue
来操作的.
而 MessageQueue
中的消息移除又有以下几个方法
void removeMessages(Handler , int , Object )
void removeMessages(Handler, Runnable,Object)
void removeCallbacksAndMessages(Handler, Object)
void removeAllMessagesLocked()
void removeAllFutureMessagesLocked()
先来看第一个.
MessageQueue.removeMessages(Handler , int , Object )
MessageQueue.java 641 行
void removeMessages(Handler h, int what, Object object) {
//分析 1
if (h == null) {
return;
}
synchronized (this) {
//分析 2
Message p = mMessages;
//分析 3
while (p != null && p.target == h && p.what == what&& (object == null || p.obj == object)) {
Message n = p.next;
mMessages = n;
p.recycleUnchecked();
p = n;
}
//分析 4
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;
}
}
}
- 分析
- 对传进来的
Handler
做非空判断, 如果传进来的Handler
为空, 则直接返回.- 获取消息链表的头元素
- 如果从消息链表获取的头部元素符合删除条件的
Message
, 就从头开始遍历删除所有符合条件的Message
,并放入消息池.- 如果消息链表的头部元素不符合分析 3, 或者在执行完分析 3 后,当前的
Message
不符合条件. 就会到分析 4 中, 判断当前Message
的下一个消息是否符合条件.
从消息队列中移除 Message
的操作就是遍历消息队列然后移除所有符合条件的 Message
. 但是这里有个细节. 从代码中可以看出移除是分了两步操作. 第一次先判断符合删除条件的 Message
是不是从消息队列的头部就开始有了, 这时候会修改 mMessage
指向的问题, 而 mMessage
代表的就是整个消息链表, 排除了第一种情况之后, 剩下的就是继续遍历队列移除剩余符合条件的 Message
, 其他重载方法也基本类似这样的流程, 不同的就是条件不同而已. 下面直接分析 removeAllFutureMessagesLocked()
这个方法.
MessageQueue.removeAllFutureMessagesLocked()
MessageQueue.java 752 行.
private void removeAllFutureMessagesLocked() {
//分析 1
final long now = SystemClock.uptimeMillis();
//分析 2
Message p = mMessages;
if (p != null) {
//分析 3
if (p.when > now) {
removeAllMessagesLocked();
} else {
//分析 4
Message n;
for (;;) {
n = p.next;
if (n == null) {
return;
}
if (n.when > now) {
break;
}
p = n;
}
//分析 5
p.next = null;
do {
p = n;
n = p.next;
p.recycleUnchecked();
} while (n != null);
}
}
}
删除所有未来的消息.
- 分析
- 获得当前时间(从手机开机到现在的时间)
- 获取消息队列中消息链表的头元素赋值给
p
- 如果
p
的执行时间大于当前时间, 就删除链表中的所有数据. (因为链表中的排序是有序的, 如果第一个执行时间都大于当前时间了, 意味着整个链表所有元素的执行时间都大于当前时间)- 如果消息队列中
p
的执行时间小于当前时间, 则说明需要遍历消息队列通过对比时间找到合适的消息进行移除.- 找到合适的消息后, 就开始移除这个消息到消息队列尾部的所有元素.
3. 查看消息是否存在
入口同样也是在 Handler
中. 有 3 个入口
// Handler.java
public final boolean hasMessages(int what) {
return mQueue.hasMessages(this, what, null);
}
public final boolean hasMessages(int what, Object object) {
return mQueue.hasMessages(this, what, object);
}
public final boolean hasCallbacks(Runnable r) {
return mQueue.hasMessages(this, r, null);
}
内部同样调用的也是 MessageQueue.hasMessages
方法.
MessageQueue.hasMessages(Handler h, int what, Object object)
MessageQueue.java 590 行
boolean hasMessages(Handler h, int what, Object object) {
//分析 1
if (h == null) {
return false;
}
synchronized (this) {
//分析 2
Message p = mMessages;
//分析 3
while (p != null) {
if (p.target == h && p.what == what && (object == null || p.obj == object)) {
return true;
}
p = p.next;
}
return false;
}
}
- 分析
- 判断传入进来的
Handler
是否为null
, 如果null
就直接返回false
. 表示没有找到.- 获得消息队列中的头部元素
- 遍历消息队列链表中所有的消息, 如有有消息符合指定条件, 则返回
true
. 若遍历结束也没有, 就返回false
剩下的也都基本是这个流程, 就不再分析. 不同的只是筛选条件不同.
到这里, Android 消息机制的 消息入队, 消息取出, 消息处理, 消息移除, 已经全部分析学习完了, 下一章将学习一个新的内容 HandlerThread.