Android Message源码阅读
Handler是Android中一种处理线程消息循环的机制,而 Message 是Handler用来放消息的包装。总得来说,Message作为一个用于封装消息的对象,逻辑并不复杂。
public final class Message implements Parcelable { // Source Code here}
Android常用序列化有 Serializable 和 Parcelable 两种,该类继承Parcelable接口表明支持序列化。简单说,前者用的时间比较长且范围更广,但是序列化过程中产生大量小对象;后者性能好,但是需要手动实现4个必须方法,范围也没有前者广。
一、成员变量
用一个标志来区分不同的消息的身份。不同的Handler里使用相同what
值的不同消息不会弄混。一般用十六进制形式表示,阅读起来比较容易。
public int what; // 0x01
arg1
和arg2
都是类中可选的变量存储位置,可以方便地用来存放两个数值,这样就不用访问obj
对象就能读取变量。
public int arg1; public int arg2;
obj
用来保存一个需要的对象,在处理的时候取出来使用。
public Object obj; // 用来保存对象public Messenger replyTo; // 回复跨进程的Messengerpublic int sendingUid = -1; // Messenger发送时使用static final int FLAG_IN_USE = 1 << 0; // 正在使用标志值static final int FLAG_ASYNCHRONOUS = 1 << 1; // 异步标志值static final int FLAGS_TO_CLEAR_ON_COPY_FROM = FLAG_IN_USE;int flags; // 消息标志,上面三个常量 FLAG_* 用在这里long when; // 估计和arg1、arg2性质一样,存时间戳Bundle data; // 存放BundleHandler target; // 存放Handler实例Runnable callback; // 消息的回调操作Message next; // 消息池用链表的方式存储private static final Object sPoolSync = new Object(); // 消息池同步公用标志private static Message sPool; // 消息池private static int sPoolSize = 0; // 消息池已缓存数量private static final int MAX_POOL_SIZE = 50; // 消息池最大容量private static boolean gCheckRecycle = true; // 该版本系统是否支持回收标志位
二、消息体获取
从消息池里取可以复用的消息对象。方法体有一个同步代码块,对象sPoolSync
作为锁标志,避免不同线程取到同一个消息体导致消息紊乱。如果没有可复用的对象,就新建一个消息体返回。
我们可以手动创建一个消息对象,但是最好从obtain()
中获取缓存好的消息体,避免造成多余对象创建。
public static Message obtain() { synchronized (sPoolSync) { if (sPool != null) { Message m = sPool; sPool = m.next; m.next = null; m.flags = 0; // 移除使用中标志 sPoolSize--; return m; } } return new 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;}
返回一个消息,这个消息已经设置好发送的目标
public static Message obtain(Handler h) { Message m = obtain(); m.target = h; return m;}
下面都是获取消息体然后设置消息体参数的方法,就是public static Message obtain()
的重载。
public static Message obtain(Handler h, Runnable callback) { Message m = obtain(); m.target = h; m.callback = callback; return m;}public static Message obtain(Handler h, int what) { Message m = obtain(); m.target = h; m.what = what; return m;}public static Message obtain(Handler h, int what, Object obj) { Message m = obtain(); m.target = h; m.what = what; m.obj = obj; return m;}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;}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) { gCheckRecycle = false; }}
对象使用完毕就会调用recycleUnchecked()
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; // 最多缓存50个消息体,多余的GC synchronized (sPoolSync) { if (sPoolSize < MAX_POOL_SIZE) { next = sPool; sPool = this; sPoolSize++; } }}
四、copyFrom
从一个消息体复制参数到另一个消息体。
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; }}
五、Getter & Setter
public void setTarget(Handler target) { this.target = target;}public Handler getTarget() { return target;}public long getWhen() { return when;}public Runnable getCallback() { return callback;}public Bundle getData() { if (data == null) { data = new Bundle(); } return data;}// peekData()对比getData()public Bundle peekData() { return data;}public void setData(Bundle data) { this.data = data;}// 把消息发送到Handler,配合obtain()使用,这样target不为空。public void sendToTarget() { target.sendMessage(this);}public void setAsynchronous(boolean async) { if (async) { flags |= FLAG_ASYNCHRONOUS; } else { flags &= ~FLAG_ASYNCHRONOUS; }}
六、标志位
public boolean isAsynchronous() { return (flags & FLAG_ASYNCHRONOUS) != 0;}boolean isInUse() { return ((flags & FLAG_IN_USE) == FLAG_IN_USE);}void markInUse() { flags |= FLAG_IN_USE;}
七、Parcelable实现
实现Parcelable接口的四个固定方法 CREATOR
、describeContents()
、writeToParcel()
、readFromParcel()
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();}
更多相关文章
- UML详解:解析Android消息处理机制:Handler/Thread/Looper & Messag
- Android 访问Webservice接口,参数对象不能串行化问题解决(java.lan
- Activity之间传递对象
- Android仿QQ消息列表ListView滑动删除效果
- Android EventBus 传递消息
- [Android] 监听系统网络连接打开或者关闭的消息
- android屏幕监听,手机是否处于锁屏状态,在锁屏之上弹出Toast.makeT
- Android intent 传递数组对象序列化
- Android自动化工具Monkeyrunner使用(六) —— 根据ID查找对象