1 源码注释
// 定义一个包含描述和任务数据对象的message,且message能被handler发送,这个对象包含两个extra int域和一个extra object域,它们能让你在很多情况下不必做分配工作。
// 虽然Message的构造器是public的,但是最好是通过Message.obtain()方法获取Handler.obtainMessage()来获取,这样能复用Message对象,减轻创建Message对象所造成的消耗。
public final class Message implements Parcelable {
/**
* 用户自定义一个code,用例区分这个Message是什么内容。
* 每个Handler有它自己的名字空间用于what,所以你不必担心和其它Handler的Message.what会冲突
*/
public int what;
/**
* 如果你只想在Messag里放int数据,你可以直接用这个变量来存放
*/
public int arg1;
/**
* 如果你只想在Messag里放int数据,你可以直接用这个变量来存放
*/
public int arg2;
/**
* 要发给接收者的对象,当使用Messager去发Message进行跨进程通信时,如果它包含Parceable,那么这个变量不能为空。 对于其它的数据传输请用setData()
*/
public Object obj;
/**
* 可选的Messager,它可以发送此消息的答复。具体如何使用还需要取决于发送方和接收方,一般是用在跨进程通信上
*/
public Messenger replyTo;
/**
* 可选的域,用来指示发送消息的uid.这个只能对Messager发送的消息有效,否则默认都是-1
*/
public int sendingUid = -1;
/*
* 一个标志:表示这个消息是在使用
* 这个flag是在message入队时被设置,在被分发时保留设置,最后回收时也保留设置。这个flag只有在一个创建新Message或获取新Message时才能被请空,因为这是程序唯一允许修改Message内容的时间。
* 在入队和回收时用一个已在使用的Message是错误的
*/
static final int FLAG_IN_USE = 1 << 0;
/** 一个标志:表示设置message是异步的 */
static final int FLAG_ASYNCHRONOUS = 1 << 1;
/**一个标志:表示在copyFrom方法中清除标记 */
static final int FLAGS_TO_CLEAR_ON_COPY_FROM = FLAG_IN_USE;
// 放标记
int flags;
// 放时间
long when;
// 放消息内容
Bundle data;
// 接收消息的handler
Handler target;
// runable
Runnable callback;
// 单链表里下一个message
Message next;
// 对象池用的同步锁对象
public static final Object sPoolSync = new Object();
// 对象池,对象池是一个单链表,所以一个Message对象就可以代表对象池
private static Message sPool;
// 对象池大小
private static int sPoolSize = 0;
// 常量,对象池大小最多为50
private static final int MAX_POOL_SIZE = 50;
// 检查回收标志
private static boolean gCheckRecycle = true;
/**
* 获取一个新Message对象,可能是从全局对象池里获取的。
* 不用我们自己在new一个
*/
public static Message obtain() {
// 因为对象池是一个单链表,所以从链表的头部取
synchronized (sPoolSync) {// 加同步
if (sPool != null) {
Message m = sPool;
sPool = m.next;
m.next = null;
m.flags = 0; // 清空flag
sPoolSize--; // 对象池大小减一
return m;
}
}
return new Message();
}
/**
* 和obtain()方法一样,只是将传入的message内容复制到新获取的Message中返回
*/
public static Message obtain(Message orig) {
Message m = obtain();
m.what = orig.what;
m.arg1 = orig.arg1;
m.arg2 = orig.arg2;
m.obj = orig.obj;
m.replyTo = orig.replyTo;
m.sendingUid = orig.sendingUid;
if (orig.data != null) {
m.data = new Bundle(orig.data);
}
m.target = orig.target;
m.callback = orig.callback;
return m;
}
/*
* 从对象池获取一个新message,并且它的target为传入的handler
*/
public static Message obtain(Handler h) {
Message m = obtain();
m.target = h;
return m;
}
/*
* 从对象池获取一个新message,并且它的target为传入的handler,它的callback为传入的callback
*/
public static Message obtain(Handler h, Runnable callback) {
Message m = obtain();
m.target = h;
m.callback = callback;
return m;
}
/*
* 从对象池获取一个新message,并且它的target为传入的handler,它的what为传入的what
*/
public static Message obtain(Handler h, int what) {
Message m = obtain();
m.target = h;
m.what = what;
return m;
}
/*
* 从对象池获取一个新message,并且它的target,what,obj为传入的handler,what,obj
*/
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,并且它的target,what,arg1,arg2为传入的handler,what,arg1,arg2
*/
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,并且它的target,what,arg1,arg2,obj为传入的handler,what,arg1,arg2,obj
*/
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;
}
/** 更新检查回收标记 */
public static void updateCheckRecycle(int targetSdkVersion) {
if (targetSdkVersion < Build.VERSION_CODES.LOLLIPOP) {
// 如果版本小于Android5.0 则检查回收标志为false
gCheckRecycle = false;
}
}
/**
* 如果message不在使用中,则回收对象
*/
public void recycle() {
if (isInUse()) {
if (gCheckRecycle) {
throw new IllegalStateException("This message cannot be recycled because it "
+ "is still in use.");
}
return;
}
recycleUnchecked();
}
/**
* 向对象池添加一个对象
*/
void recycleUnchecked() {
flags = FLAG_IN_USE;
what = 0;
arg1 = 0;
arg2 = 0;
obj = null;
replyTo = null;
sendingUid = -1;
when = 0;
target = null;
callback = null;
data = null;
synchronized (sPoolSync) {
if (sPoolSize < MAX_POOL_SIZE) {
next = sPool;
sPool = this;
sPoolSize++;
}
}
}
/**
* 复制指定Message的内容
*/
public void copyFrom(Message o) {
this.flags = o.flags & ~FLAGS_TO_CLEAR_ON_COPY_FROM;
this.what = o.what;
this.arg1 = o.arg1;
this.arg2 = o.arg2;
this.obj = o.obj;
this.replyTo = o.replyTo;
this.sendingUid = o.sendingUid;
if (o.data != null) {
this.data = (Bundle) o.data.clone();
} else {
this.data = null;
}
}
/**
* Return the targeted delivery time of this message, in milliseconds.
* 返回消息被分发的时间,用毫秒表示
*/
public long getWhen() {
return when;
}
public void setTarget(Handler target) {
this.target = target;
}
/**
* 获取接收Message的Handler
*/
public Handler getTarget() {
return target;
}
/**
* 回调对象
*/
public Runnable getCallback() {
return callback;
}
/** 设置消失里的回调对象 */
public Message setCallback(Runnable r) {
callback = r;
return this;
}
/**
* 获取Bundle
*/
public Bundle getData() {
if (data == null) {
data = new Bundle();
}
return data;
}
public Bundle peekData() {
return data;
}
/**
* 设置data
*/
public void setData(Bundle data) {
this.data = data;
}
/**
* 设置what
*/
public Message setWhat(int what) {
this.what = what;
return this;
}
/**
* 将消息发给接受者Handler
*/
public void sendToTarget() {
target.sendMessage(this);
}
/**
* 消息是否是异步的
*/
public boolean isAsynchronous() {
return (flags & FLAG_ASYNCHRONOUS) != 0;
}
/**
* 设置这个消息是否是异步的
*/
public void setAsynchronous(boolean async) {
if (async) {
flags |= FLAG_ASYNCHRONOUS;
} else {
flags &= ~FLAG_ASYNCHRONOUS;
}
}
/**
* 消息是否正在使用
*/
boolean isInUse() {
return ((flags & FLAG_IN_USE) == FLAG_IN_USE);
}
/**
* 标记消息正在使用
*/
void markInUse() {
flags |= FLAG_IN_USE;
}
/** Constructor (but the preferred way to get a Message is to call {@link #obtain() Message.obtain()}).
*/
public Message() {
}
@Override
public String toString() {
return toString(SystemClock.uptimeMillis());
}
String toString(long now) {
StringBuilder b = new StringBuilder();
b.append("{ when=");
TimeUtils.formatDuration(when - now, b);
if (target != null) {
if (callback != null) {
b.append(" callback=");
b.append(callback.getClass().getName());
} else {
b.append(" what=");
b.append(what);
}
if (arg1 != 0) {
b.append(" arg1=");
b.append(arg1);
}
if (arg2 != 0) {
b.append(" arg2=");
b.append(arg2);
}
if (obj != null) {
b.append(" obj=");
b.append(obj);
}
b.append(" target=");
b.append(target.getClass().getName());
} else {
b.append(" barrier=");
b.append(arg1);
}
b.append(" }");
return b.toString();
}
void writeToProto(ProtoOutputStream proto, long fieldId) {
final long messageToken = proto.start(fieldId);
proto.write(MessageProto.WHEN, when);
if (target != null) {
if (callback != null) {
proto.write(MessageProto.CALLBACK, callback.getClass().getName());
} else {
proto.write(MessageProto.WHAT, what);
}
if (arg1 != 0) {
proto.write(MessageProto.ARG1, arg1);
}
if (arg2 != 0) {
proto.write(MessageProto.ARG2, arg2);
}
if (obj != null) {
proto.write(MessageProto.OBJ, obj.toString());
}
proto.write(MessageProto.TARGET, target.getClass().getName());
} else {
proto.write(MessageProto.BARRIER, arg1);
}
proto.end(messageToken);
}
public static final Parcelable.Creator CREATOR
= new Parcelable.Creator() {
public Message createFromParcel(Parcel source) {
Message msg = Message.obtain();
msg.readFromParcel(source);
return msg;
}
public Message[] newArray(int size) {
return new Message[size];
}
};
public int describeContents() {
return 0;
}
public void writeToParcel(Parcel dest, int flags) {
if (callback != null) {
throw new RuntimeException(
"Can't marshal callbacks across processes.");
}
dest.writeInt(what);
dest.writeInt(arg1);
dest.writeInt(arg2);
if (obj != null) {
try {
Parcelable p = (Parcelable)obj;
dest.writeInt(1);
dest.writeParcelable(p, flags);
} catch (ClassCastException e) {
throw new RuntimeException(
"Can't marshal non-Parcelable objects across processes.");
}
} else {
dest.writeInt(0);
}
dest.writeLong(when);
dest.writeBundle(data);
Messenger.writeMessengerOrNullToParcel(replyTo, dest);
dest.writeInt(sendingUid);
}
private void readFromParcel(Parcel source) {
what = source.readInt();
arg1 = source.readInt();
arg2 = source.readInt();
if (source.readInt() != 0) {
obj = source.readParcelable(getClass().getClassLoader());
}
when = source.readLong();
data = source.readBundle();
replyTo = Messenger.readMessengerOrNullFromParcel(source);
sendingUid = source.readInt();
}
}
2 设计点
2.1 Message对象池的设计
因为每个Hander可能会处理大量Message,而每次发送Message时都要构造一个Message对象肯定是不佳的做法,所以可以定义一个全局的Message对象池,当Message被消费了之后,可以把它会收到对象池,然后获取新Message填消息内容时,Message对象可以从对象池中取出。
好处:
- 减少不必要的新建对象造成的资源消耗
2.2 Message对象池的实现
对象池为什么不用map?
实现对象池有多种方式:
- 容易想到的就是用Map结构
- 用链表
- 用数组
Message对象池的结构并不是map那种结构,而是一个单链表,应该是因为单链表很容易在链表头插入和取出元素,而Map对象太重了,而且管理元素还需要key,我觉得map应该是适合存放不同类型的对象。而Message的业务只需要Message一种类型的对象池,所有采用链表。如果用数组,显而易见,数组来实现元素的插入和取出太麻烦了,而且效率也不好。
所以总结下来:选取对象池的结构:如果用于管理多类型对象,并且一个类型一个元素则优先用map(这个就有点像单例了)。如果用于单种类型多个元素,则优先用链表。
对象池操作的线程安全?
可以从源码中看到每次对象池的操作的线程安全实现是在单独一个object上加锁。
为什么要这样?
- 给Message.class加锁:对象池是一个静态变量,操作方法也是静态方法,没必要在类上加锁