创建Message的3中方式:
第一种方式:
//这种是常见的创建对象的方式,每次需要发送消息的时候都需要创建一个Message 对象,每次都要到堆内存中开辟新的存储空间,使用之后jvm再次进行回收处理
Message message = new Message();
第二种方式:
Message message = mHandler.obtainMessage();
先简单看下源码,发现其实实现的原理也是方式三,调用的是obtain()方法,所以下面着重分析obtain方法:
public final Message obtainMessage(){
return Message.obtain(this);
}
public static Message obtain(Handler h) {
Message m = obtain();
m.target = h;
return m;
}
第三种方式:
Message message = Message.obtain();
这两种方式实质上是一样的,都会有一个单链表缓存池来缓存创建的消息,如果缓存池中没有message,会创建一个新的message,如果缓存池中含有消息,则拿出来使用
Message中携带的信息
/**
* 用来区别handler发出的消息的类型
*/
public int what;
/**
* arg1 和 arg2是定义了两个整形数据,数据少的话直接用这两个即可
*/
public int arg1;
public int arg2;
/**
* 发送给接受方的任意对象,在使用跨进程的时候要注意obj不能为null
*/
public Object obj;
/**
* 在使用跨进程通信Messenger时,可以确定需要谁来接收
*/
public Messenger replyTo;
/**
* 在使用跨进程通信Messenger时,可以确定需要发消息的uid
*/
public int sendingUid = -1;
/**
* 如果数据比较多,可以直接使用Bundle进行数据的传递
*/
Bundle data;
测试代码:
Message message = Message.obtain();
message.what = 0xff;
//int
message.arg1 = 100;
//obj
message.obj = new Student("赵日天");
//bundle
Bundle bundle = new Bundle();
bundle.putString("name", "赵日天");
bundle.putInt("age", 18);
message.setData(bundle);
//发送消息
mHandler.sendMessage(message);
public class Student {
private String name;
public Student(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Log.i("msg", "handleMessage: " + msg.what);
if (msg.what == 0xff) {
Log.i("msg", "handleMessage: " + msg.arg1);
Student student = (Student) msg.obj;
Log.i("msg", "handleMessage: " + student.getName());
Bundle bundle = msg.getData();
Log.i("msg", "handleMessage: " + bundle.getString("name") + " age :" + bundle.getInt("age"));
}
}
};
输出日志
06-19 04:00:06.283 2594-2594/? I/msg: handleMessage: 255
06-19 04:00:06.283 2594-2594/? I/msg: handleMessage: 100
06-19 04:00:06.283 2594-2594/? I/msg: handleMessage: 赵日天
06-19 04:00:06.283 2594-2594/? I/msg: handleMessage: 赵日天 age :18
源码分析:
源码: 我们发现如果消息池sPool不为空的话,会从里面取出一个消息实现复用,如果为空的话,先new一个消息
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();
}
public Message() {
}
上面的方法里面相关的变量介绍:
sPoolSync 主要的目的是给Message加一个对象锁,防止多线程同时访问Message类和obtain方法,导致取出的消息发生错误
public static final Object sPoolSync = new Object();
sPool 主要是存储我们循环利用的Message单链表,这里的sPool 值得是链表的头结点
private static Message sPool;
单链表的链表的长度,即存储的Message对象的个数。
private static int sPoolSize = 0;
分析obtain:
假设消息池中含有三个消息:sPool为下图表示的样子:
1 :Message m = sPool
2 sPool = m.next;
3:m.next = null;
这时我们从上面的图中可以发现已经取出了一个消息m,并且sPool链表中的消息数量sPoolSize也由3个变为了两个,即 sPoolSize–,
recycle以及recycleUnchecked
void recycleUnchecked() {
// Mark the message as in use while it remains in the recycled object pool.
// Clear out all other details.
//这段代码主要是重置message的一些变量,以便重复使用
flags = FLAG_IN_USE;
what = 0;
arg1 = 0;
arg2 = 0;
obj = null;
replyTo = null;
sendingUid = -1;
when = 0;
target = null;
callback = null;
data = null;
//这个主要是把上面使用的重置过的message添加到sPool中以便重复利用
synchronized (sPoolSync) {
if (sPoolSize < MAX_POOL_SIZE) {
next = sPool;
sPool = this;
sPoolSize++;
}
}
}