- // 标识Message
- public int what;
-
- // 存储简单数据,如果存储复杂的数据使用setData()方法。
- public int arg1;
- public int arg2;
-
- // 发送给接收者的任意对象。
- public Object obj;
-
- // 回复给发送者,用于跨进程双向通信。发送message时给其replyTo赋值,接收到该message的进程,可以通过message.replyTo向发送方进程发送message,从而实现双向通信。
- public Messenger replyTo;
-
- public static final int UID_NONE = -1;
- // 可选字段,表示发送消息的uid。这只对Messenger发布(跨进程发布)的消息有效;否则,它就是-1。
- public int sendingUid = UID_NONE;
- // 可选字段,指示导致该消息进入队列的uid。
- public int workSourceUid = UID_NONE;
-
- // 在用标记
- /*package*/ static final int FLAG_IN_USE = 1 << 0;
- // 异步标记
- /*package*/ static final int FLAG_ASYNCHRONOUS = 1 << 1;
- // copy的清空标记
- /*package*/ static final int FLAGS_TO_CLEAR_ON_COPY_FROM = FLAG_IN_USE;
- // 标记位
- @UnsupportedAppUsage
- /*package*/ int flags;
-
- // 执行时刻,时刻基于SystemClock.uptimeMillis。
- @UnsupportedAppUsage
- public long when;
-
- // 存储复杂的数据
- /*package*/ Bundle data;
-
- // 消息的目标处理器Handler,即由此Handler处理此消息。
- @UnsupportedAppUsage
- /*package*/ Handler target;
-
- // 表示要处理的任务Callback,由Runnable实现,通过handler.post Runnable的时候,Runnable会被存放在Message中,分发的时候再进行回调通知。
- @UnsupportedAppUsage
- /*package*/ Runnable callback;
-
- // 下个消息,用于实现链表结构。
- @UnsupportedAppUsage
- /*package*/ Message next;
-
- // 消息池的同步锁对象,用户消息池的消息获取(obtain()方法)和消息回收(recycleUnchecked()方法)。
- /** @hide */
- public static final Object sPoolSync = new Object();
- // 消息池链表的头,用于操作(增删改查)链表。
- private static Message sPool;
- // 消息池中消息的数量
- private static int sPoolSize = 0;
- // 消息池中消息的最大数量,为50个。
- private static final int MAX_POOL_SIZE = 50;
- // 是否检查消息的回收(recycle()方法),默认true,如果检查并且有问题,则抛出异常。
- private static boolean gCheckRecycle = true;
- 复制代码
说明:
Message为什么需要持有Handler,因为Message需要知道是哪个Handler要处理它。
想要使用、发送Message,首先要创建Message,所以我们接下来看下它是如何被创建的。
- public Message() {
- }
- 复制代码
直接创建一个Message对象,之后可以设置它的属性,未使用复用,不推荐使用。
Message.obtain()
- public static Message obtain() {
- // 使用同步保证线程安全,因为此方法可以在任意线程调用。
- synchronized (sPoolSync) {
- if (sPool != null) {
- // 消息池头不为空,说明队列有内容,从中获取一条消息并返回。缓存的
- Message m = sPool; // 消息池的Head元素
- sPool = m.next; // 缓存池Head为下个元素(移除m)
- m.next = null; // 断开链接
- m.flags = 0; // 清除在用标记
- sPoolSize--; // 池数量减1
- return m; // 返回此消息
- }
- }
- // 消息池头为空,说明队列没有内容,直接创建一条消息并返回。
- return new Message();
- }
- 复制代码
Message.obtain()为静态方法,内部用了全局消息池,使用了复用,推荐使用。
说明:
- 从消息池中获取消息,它会获取队列的第一条消息,并将此消息从此队列中移除。
Message.obtain(Message)
- public static Message obtain(Message orig) {
- // 获取消息
- Message m = obtain();
- // 将orig的值复制到新消息中
- m.what = orig.what;
- m.arg1 = orig.arg1;
- m.arg2 = orig.arg2;
- m.obj = orig.obj;
- m.replyTo = orig.replyTo;
- m.sendingUid = orig.sendingUid;
- m.workSourceUid = orig.workSourceUid;
- if (orig.data != null) {
- m.data = new Bundle(orig.data);
- }
- m.target = orig.target;
- m.callback = orig.callback;
-
- return m;
- }
- 复制代码
与Message.obtain()相同,但将现有Message(包括其target)的值复制到新的消息中。
Message.obtain(Handler)
- public static Message obtain(Handler h) {
- Message m = obtain();
- m.target = h;
-
- return m;
- }
- 复制代码
与Message.obtain()相同,但设置了target成员的值。
Message.obtain(Handler, Runnable)
- public static Message obtain(Handler h, Runnable callback) {
- Message m = obtain();
- m.target = h;
- m.callback = callback;
-
- return m;
- }
- 复制代码
与Message.obtain()相同,但设置了target和callback成员的值。
Message.obtain(Handler, int)
- public static Message obtain(Handler h, int what) {
- Message m = obtain();
- m.target = h;
- m.what = what;
-
- return m;
- }Message.
- 复制代码
与Message.obtain()相同,但设置了target和what成员的值。
Message.obtain(Handler, int, Object)
- 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.obtain()相同,但设置了target、what和obj成员的值。
Message.obtain(Handler, int, int, int)
- 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.obtain()相同,但设置了target、what、arg1和arg2成员的值。
Message.obtain(Handler, int, int, int, Object)
- 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.obtain()相同,但设置了target、what、arg1、arg2和obj成员的值。
Message的创建,有两种方式:new Message、Message.obtain(),Message.obtain()内部使用了复用,推荐使用。
由于Message.obtain()方式创建内部使用了复用,所以我们接下来看下它是如何被回收的。
- public void recycle() {
- // 判断是否在使用中
- if (isInUse()) {
- // 在使用中,直接返回,不进行回收。
- if (gCheckRecycle) {
- // gCheckRecycle为true,为检查消息的回收,并且回收时正在使用(有问题),则抛出异常。
- throw new IllegalStateException("This message cannot be recycled because it "
- + "is still in use.");
- }
- return;
- }
- // 不在使用中,进行回收。
- recycleUnchecked();
- }
- 复制代码
recycle()方法,为检查回收,如果此消息处于使用状态,则不进行回收,否则调用recycleUnchecked()直接进行回收。
isInUse()方法的使用看后面-其它-InUse,我们接下来看下gCheckRecycle属性,它在updateCheckRecycle()方法内进行更改。
- public static void updateCheckRecycle(int targetSdkVersion) {
- if (targetSdkVersion < Build.VERSION_CODES.LOLLIPOP) {
- // 小于SDK 21,为false。
- gCheckRecycle = false;
- }
- }
- 复制代码
updateCheckRecycle()方法,为更新gCheckRecycle的值。gCheckRecycle默认为true,updateCheckRecycle()方法在ActivityThread的handleBindApplication()方法(绑定App)内调用,即gCheckRecycle在targetSdkVersion小于21为false(不检查),大于、等于21为ture(检查)。
- void recycleUnchecked() {
- // 将此消息标记为在用,并判断是否添加到消息池中。
- // 清除所有属性
- flags = FLAG_IN_USE;
- what = 0;
- arg1 = 0;
- arg2 = 0;
- obj = null;
- replyTo = null;
- sendingUid = UID_NONE;
- workSourceUid = UID_NONE;
- when = 0;
- target = null;
- callback = null;
- data = null;
-
- // 同步,保证线程安全。
- synchronized (sPoolSync) {
- if (sPoolSize < MAX_POOL_SIZE) {
- // 小于最大值,则进行添加,把此Message添加到链表的头部。
- next = sPool; // 此Message的next指向链表的Head
- sPool = this; // 链表的Head为此Message
- sPoolSize++; // 消息池数量加1
- }
- }
- }
- 复制代码
recycleUnchecked()方法,为不检查回收,会清除消息的所有属性,以完成释放,并判断如果消息池的消息数量没有到达最大数量,则进行添加,以完成回收。
说明:
- 从消息池中添加消息,它会将此消息添加到队列的头部,并将此消息作为新的头。
Message的回收,有两种方式:recycle()检查回收、recycleUnchecked()不检查回收。recycle(),判断了消息如果处于使用状态,则不进行回收,否则调用recycleUnchecked()进行回收。recycleUnchecked(),会清除消息的所有属性,并判断如果消息池数量没到消息池最大数量,则进行添加(添加到消息池的链表的头部)。
由于Message实现了Parcelable接口,所以Message可以跨进程传输,所以我们接下来看下它的具体实现。
- public void writeToParcel(Parcel dest, int flags) {
- if (callback != null) {
- // callback不能跨进程传输,抛出异常。
- throw new RuntimeException(
- "Can't marshal callbacks across processes.");
- }
- dest.writeInt(what);
- dest.writeInt(arg1);
- dest.writeInt(arg2);
- if (obj != null) {
- // obj不为空,跨进程传输任意对象,必须实现Parcelable接口,否则抛出异常。
- try {
- Parcelable p = (Parcelable)obj;
- dest.writeInt(1); // 传入1,标记有存入obj对象。
- dest.writeParcelable(p, flags); // 写入obj对象
- } catch (ClassCastException e) {
- throw new RuntimeException(
- "Can't marshal non-Parcelable objects across processes.");
- }
- } else {
- dest.writeInt(0); // 传入0,标记没有存入obj对象。
- }
- dest.writeLong(when);
- dest.writeBundle(data);
- Messenger.writeMessengerOrNullToParcel(replyTo, dest); // 使用Messenger进行写入
- dest.writeInt(sendingUid);
- dest.writeInt(workSourceUid);
- }
- 复制代码
- private void readFromParcel(Parcel source) {
- what = source.readInt();
- arg1 = source.readInt();
- arg2 = source.readInt();
- if (source.readInt() != 0) {
- // 有存入obj对象,进行读取。
- obj = source.readParcelable(getClass().getClassLoader());
- }
- when = source.readLong();
- data = source.readBundle();
- replyTo = Messenger.readMessengerOrNullFromParcel(source); // 使用Messenger进行读取
- sendingUid = source.readInt();
- workSourceUid = source.readInt();
- }
- 复制代码
Message的跨进程通讯,callback不能有值,obj如有值则必须实现Parcelable接口。
Message的when、target、callback、data属性对外提供了set、get方法,我们接下来看下它们的实现。
- public long getWhen() {
- return when;
- }
- 复制代码
- public void setTarget(Handler target) {
- this.target = target;
- }
-
- public Handler getTarget() {
- return target;
- }
- 复制代码
- public Runnable getCallback() {
- return callback;
- }
- 复制代码
- public Bundle getData() {
- if (data == null) {
- data = new Bundle();
- }
- return data;
- }
-
- public Bundle peekData() {
- return data;
- }
-
- public void setData(Bundle data) {
- this.data = data;
- }
- 复制代码
- 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;
- this.workSourceUid = o.workSourceUid;
-
- if (o.data != null) {
- this.data = (Bundle) o.data.clone();
- } else {
- this.data = null;
- }
- }
- 复制代码
将指定Message的属性,复制到当前Message中。
- public void sendToTarget() {
- target.sendMessage(this);
- }
- 复制代码
将此消息发送给自己的目标Handler,如果未设置此字段,则抛出空指针异常。
- public boolean isAsynchronous() {
- return (flags & FLAG_ASYNCHRONOUS) != 0;
- }
- 复制代码
isAsynchronous()方法,判断消息是否是异步的,如果是,则返回true。
- public void setAsynchronous(boolean async) {
- if (async) {
- flags |= FLAG_ASYNCHRONOUS;
- } else {
- flags &= ~FLAG_ASYNCHRONOUS;
- }
- }
- 复制代码
setAsynchronous()方法,设置消息是否是异步的,这意味着它不受Looper同步屏障的影响。
说明:
- 消息,分为同步消息和异步消息,默认为同步消息。
- 同步屏障,会屏障同步消息,确保只有异步消息执行。
- 某些操作(比如视图失效)可能会在
Looper的消息队列中引入同步屏障,以阻止后续消息在满足某些条件之前被传递。在view invalidation的情况下,调用android.view.View.invalidate后发布的消息会被一个同步屏障挂起,直到下一帧准备被绘制。同步屏障确保在恢复之前完全处理了无效请求。- 异步消息免于同步屏障。它们通常表示中断、输入事件和其它必须独立处理的信号,即使其它工作已经暂停。
- 请注意,异步消息可能是按同步消息的顺序交付的,尽管它们之间总是按顺序交付的。如果这些消息的相对顺序很重要,那么它们可能一开始就不应该是异步的,谨慎使用。
- /*package*/ boolean isInUse() {
- return ((flags & FLAG_IN_USE) == FLAG_IN_USE);
- }
- 复制代码
isInUse()方法,判断是否处于使用状态。
- /*package*/ void markInUse() {
- flags |= FLAG_IN_USE;
- }
- 复制代码
markInUse()方法,标记处于使用状态。