前言
Message位于android/os/Message.java文件中,用于创建Message对象的构造方法
一系列用于获取Message对象的obtain()方法,共计8个
接下来我们分析构造方法,以及所有的obtain()方法!
Message构造方法分析
public Message() {
}
Message的默认构造方法,官方明确告知创建Message对象时不要使用构造方法,而是使用它提供的obtain系列方法,这是为什么呢?在Message的第二篇文章中,我们将分析Message池的概念!
obtain()方法分析
public static Message obtain() {
synchronized (sPoolSync) {
if (sPool != null) {
Message m = sPool;
sPool = m.next;
m.next = null;
m.flags = 0; // clear in-use flag
sPoolSize--;
return m;
}
}
return new Message();
}
用于获取一个Message对象的静态方法,无需传入参数,多数情况下该方法都会从消息池中取出一个Message对象,特殊情况下也会使用new创建一个Message对象,我们一起学习一下这些业务逻辑
1、获取sPoolSync的对象锁,开始执行获取Message对象的逻辑
sPoolSync是一个常量(static final修饰),它指向一个Object对象,sPoolSync对象在这里专门是作为对象锁来使用的,每个对象都有一个对应的Monitor Lock,线程只有获得对象所关联的Monitor锁,才能执行临界区的代码,而没有获得对象锁的线程,将在synchronized修饰的临界区(方法或代码块)入口处被阻塞,处于一个BLOCKED状态,只能等待持有对象锁的线程释放了对象锁后才能进入临界区继续执行代码。当一个线程获得sPoolSync对象关联的Monitor锁后,首先检查sPool是否不为null,sPool是Message类持有的一个静态变量,该静态变量指向一个Message对象,当sPool不为空时,首先获得sPool指向的Message对象,然后赋值给临时变量m负责存储上,每个Message对象可以通过它的实例变量next持有另外一个Message对象(典型的单链表),此时通过m.next,将下一个Message对象赋值静态变量sPool持有上,sPool指向的对象永远是单链表的第一个元素,接着当前Message对象m持有的next指向null,表示断开链接,接着又把当前Message对象持有的m持有的flags赋值为0(flags用于标记Message对象为未使用状态),这等同于做了单链表头结点的删除,Message类持有的sPoolSize则是记录一个单链表的长度,此时因为已经单链表中取出来一个结点元素,所以它进行了sPoolSize--的操作,最后向调用方返回从单链表取出的Message对象m!
2、Message类持有的静态变量sPool 为空时,说明消息池中没有Message对象,则会执行new Message()的代码,返回一个Message对象
现在我知道为什么官方推荐用obtain系列的静态方法了,Message类持有了一个单链表,头引用是sPool,而这个单链表就是Message类为节省内存空间,缓存的一组Message对象(以单链表结构存储,并使用了静态变量sPool,保证指向的第一个结点对象不会被gc回收,也就保证一个一个的后继结点对象不会被回收)
obtain()方法分析(重载方法:1个参数)
public static Message obtain(Handler h) {
Message m = obtain();
m.target = h;
return m;
}
用于从消息池中返回一个持有Handler对象的Message对象,传入的参数为Handler对象,用于交给Message持有
1、从消息池中获取一个Message对象,并保存在局部变量中
首先调用静态方法obtain()获得一个Message对象并交由临时变量m存储上
2、为Message对象持有一个Handler对象
为Message对象持有的实例变量target,赋值为传入的Hander对象
3、向调用者返回Message对象
obtain()方法分析(重载方法:2个参数)
public static Message obtain(Handler h, int what) {
Message m = obtain();
m.target = h;
m.what = what;
return m;
}
用于返回一个从消息池中取出的Message对象,这个Message对象持有了传入的Handler对象与一个int值what
方法体中,与上方代码类似,此处不再详述,唯一区别是Message对象多持有了一个int值
obtain()方法分析(重载方法:4个参数)
public static Message obtain(Handler h, int what, int arg1, int arg2) {
Message m = obtain();
m.target = h;
m.what = what;
m.arg1 = arg1;
m.arg2 = arg2;
return m;
}
同样与上方的方法功能相似,不同的是:返回的Message对象多持有了2个int参数,一个是传入的arg1、另一个传入的arg2
obtain()方法分析(重载方法:5个参数)
public static Message obtain(Handler h, int what,
int arg1, int arg2, Object obj) {
Message m = obtain();
m.target = h;
m.what = what;
m.arg1 = arg1;
m.arg2 = arg2;
m.obj = obj;
return m;
}
传入的参数会依次赋值给Message对象m持有的5个实例变量,target、what、arg1、arg2、obj,最后返回缓存池中获取的Message对象
obtain()方法分析(重载方法:2个参数,且参数类型不同)
public static Message obtain(Handler h, Runnable callback) {
Message m = obtain();
m.target = h;
m.callback = callback;
return m;
}
用于返回一个Message对象,该Message对象持有一个Handler对象,一个Runnable对象
obtain方法分析(重载方法:3个参数)
public static Message obtain(Handler h, int what, Object obj) {
Message m = obtain();
m.target = h;
m.what = what;
m.obj = obj;
return m;
}
内部调用类似……此处省略…………
Message对象持有的实例变量介绍
public int what;
public int arg1;
public int arg2;
public Object obj;
public Messenger replyTo;
public int sendingUid = -1;
1、前面4个实例变量是Message对象携带数据的实例变量,我们可以为其显式的赋值
what:用于持有一个int值
arg1:用于持有一个int值
arg2:用于持有一个int值
obj:用于持有一个Object对象
2、后面2个实例变量是Messager机制(进程间通信方式)中会用到的实例变量
replyTo:用于持有一个Messenger对象
sendingUid:用于持有一个int值,表示进程的用户id
/*package*/ int flags;
/*package*/ long when;
/*package*/ Bundle data;
/*package*/ Handler target;
/*package*/ Runnable callback;
/*package*/ Message next;
6个包级访问的实例变量
flags:负责标记Message的状态
when:负责存储消息执行的延迟时间
data:负责持有Bundle对象
target:负责持有发送它的Handler对象
callback:负责持有传入的Runnable对象
next:负责持有构建缓存池时指向的下一个Message对象(单链表)
总结
1、Message类持有一个sPool静态变量,它永远指向一个单链表的头引用,该sPool组成的单链表用于在内存中缓存使用过的Message对象,可以节省内存空间、可以节省创建对象的开销(这要单独开一篇源码分析文章)
2、所有需要传入参数的静态方法obtain()的内部均调用了无参数的静态方法obtain(),无参数的静态方法obtain()会从Message消息池中取出一个Message对象
3、不要使用new的方式创建Message对象,因为系统帮我们缓存了一批Message对象!(内存缓存)