基于 Android 7.1.1 源码,分析 Message 的架构和原理。
1 成员变量
1 | public int what; |
用于标识 Message!
1 | public int arg1; |
用于传递简单的整型数据,如果想传递复杂的数据使用 Bundle
1 | public Object obj; |
用于发送任意对象,如果要用 Message 进行跨进程通信,obj 必须实现序列化接口!
1 | public Messenger replyTo; |
用于跨进程双向通信,接受到该 message 的进程,可以通过 Message.replyTo 向发送方进程发送 message,从而实现双向通信!
这个在分析 Messenger 的时候会看到!
1 | public int sendingUid = -1; |
发送方的 uid,只有在通过 Messenger 跨进程通信的时候才有效,否则为 -1;
1 | int flags; |
Message 的标志位,可以取如下的值;
static final int FLAG_IN_USE = 1 << 0:用于标识当前的 Message 处于使用状态,当 Message 处于消息队列中、处于消息池中或者 Handler 正在处理该 Message 的时候,它就处于使用状态;
static final int FLAG_ASYNCHRONOUS = 1 << 1:用于标识当前的 Message 是异步的;
static final int FLAGS_TO_CLEAR_ON_COPY_FROM = FLAG_IN_USE:当调用 copyFrom 方法的时候,会去掉 FLAG_IN_USE 标志位!
1 | long when; |
Message 的分发时间;
1 | Bundle data; |
用于传输比较复杂的数据;
1 | Handler target; |
表示消息的目标处理 Handler!
1 | Runnable callback; |
表示要处理的任务 Runnable,通过 handler post Runnable 的时候,Runnable 会被封装成一个 Message,如果要用 Message 进行跨进程通信,callback 必须为 null,因为其不能序列化!!
1 | // sometimes we store linked lists of these things |
1 | private static final Object sPoolSync = new Object(); |
用于同步的锁对象!
1 | private static Message sPool; |
静态变量,我们知道 Handler 发送过的 message 会被缓存到消息池中,方便复用,其实消息池也是一个列表,sPool 是这个链表的头元素!!
1 | private static int sPoolSize = 0; |
静态变量,用于记录消息池中 Message 的数量,也就是链表的长度,其最大不能超过 MAX_POOL_SIZE 规定的大小!
1 | private static final int MAX_POOL_SIZE = 50; |
消息池中 Message 的最大数量!
1 | private static boolean gCheckRecycle = true; |
2 create Message
想要发送 Message,首先要创建 Message,创建分为 2 种:
- 直接创建;
- 复用已有消息;
下面我们来分别看看;
2.1 new Message
直接创建,能够保证我们每次创建的都是一个新的消息对象:
1 | public Message() { |
构造器很简单,没有多么复杂,我们可以创建一个 Message 对象,然后设置它的属性:1
2
3
4
5
6Message msg = new Message();
Bundle b = new Bundle();
b.putString("name", "coolqi");
b.putString("face", "cool");
msg.setData(b);
mHandler.sendMessage(msg);
这里就不多说了!
2.2 Message.obtain
复用已有消息,我们知道 handler 会将发送过的消息,保存到一个消息池中,便于复用!
Message 提供了多个 obtain 用于复用一个 Message!
1 | public static Message obtain() {...} |
上面的多个 obtain 都会先尝试从消息池中获取一个缓存的消息,如果找不到,再创建一个新的消息,然后用传入的参数更新这个消息对应的属性值,并返回!
1 | public static Message obtain() { |
代码很简单,不多了!
3 recycle Message
回收一个 Message 分为 2 种情况,一种是安全的回收,一种是不安全的回收!
3.1 safe recycle
安全的回收:
1 | public void recycle() { |
安全回收在回收 Message 之前会先检查 Message 是否处于使用状态,处于使用状态下是不能回收的!!
recycle() 在判断安全后,会调用 recycleUnchecked() 进行回收!
1 | /*package*/ boolean isInUse() { |
上面的方法用于判断 Message 是否在使用中!
gCheckRecycle 属性在 SDK 21 以及以后默认为 true,他用来决定在回收时如果正在使用,是否抛出异常!
1 | /** @hide */ |
上面是具体的判断方法!
3.2 unsafe recycle
不安全的回收:
1 | void recycleUnchecked() { |
可以看到 recycleUnchecked() 会重置掉 Message 的属性!
4 跨进程传输
由于 Message 实现了 Parcelable 接口,所以可以序列化,跨进程传输数据,我们知道信使 Messenger 就是通过 Message 来实现跨进程通信的!
4.1 writeToParcel
序列化方法:
1 | public void writeToParcel(Parcel dest, int flags) { |
如果 Message 设置了 Runnable callback,那么不能序列化!
4.2 readFromParcel
反序列化方法:
1 | private void readFromParcel(Parcel source) { |
对于 Messenger 的内容,我们会单独开一篇文章来分析!
5 其他方法
Message 提供了一些其他的方法:
- copyFrom 用于将一个 Message 的属性 copy 到另一个 Message 中:
1 | public void copyFrom(Message o) { |
- 异步相关的方法:
1 | public boolean isAsynchronous() { |
以及一些其他的用于 get 属性,打印属性的方法,这里就不多说了!!