handler源码分析之Message类

上一篇文章分析Handler类,Handler发送一个Message对象给MessageQueue,这篇文章就看看Message对象里面都封装了什么。

Message类的描述
/**
 * 
 * Defines a message containing a description and arbitrary data object that can be
 * sent to a {@link Handler}.  This object contains two extra int fields and an
 * extra object field that allow you to not do allocations in many cases.  
 *
 * <p class="note">While the constructor of Message is public, the best way to get
 * one of these is to call {@link #obtain Message.obtain()} or one of the
 * {@link Handler#obtainMessage Handler.obtainMessage()} methods, which will pull
 * them from a pool of recycled objects.</p>
 */
public final class Message implements Parcelable {

翻译:定义一个Message,包含发送给Handler的描述,和任意数据对象,该对象包括两个额外的字段 int和object,允许你在一定的情况下,不发送Message。
虽然Message的构造是公共的,但是最好使用Message.obtain()或者使用Handler#obtainMessage Handler.obtainMessage()调用,这样会从回收池中取出一个对象。

Message实现了Parcelable可序列化
作用:
1)永久性保存对象,保存对象的字节序列到本地文件中;
2)通过序列化对象在网络中传递对象;
3)通过序列化在进程间传递对象。

字段
  • public int what

自己定义的表识,区分发送的是什么消息。每个Handler都有自己的命名空间,所以不用担心和其它程序的发生冲突。

  • public int arg1 arg2

如果只需要存储几个整数值,建议使用arg1 arg2 ,而不是使用setData方法。

  • public Object obj

发送给Handler的任意对象。

  • public Messenger replyTo

可选的Messenger,可以发送对此消息的回复。 究竟如何使用的语义取决于发送者和接收者。

  • public int sendingUid = -1;

指示发送消息的uid的可选字段。 这仅适用于由{@link Messenger}发布的消息; 否则,它将是-1。

  • 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

在copyFrom方法中清除标志

  • Handler target

这个target其实就是你发送出消息的handler,根据这个target可以知道你的消息要返回给那个handler。

  • /package/ int flags;

  • /package/ long when;

  • /package/ Bundle data;

  • /package/ Runnable callback;

  • // sometimes we store linked lists of these things
    /package/ Message next;

方法
  • obtain()
/**
     * Return a new Message instance from the global pool. Allows us to
     * avoid allocating new objects in many cases.
     */
    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();
    }

if (sPoolSize < MAX_POOL_SIZE) {
                next = sPool;
                sPool = this;
                sPoolSize++;
            }

从全局池中返回一个新的Message实例,允许我们在很多情况下避免分配新的对象。
如果对象池中没有Message对象就会new出一个新的对象,如果有就复用对象池中的Message。这个对象池的最大容量是50个。

  • 其它的obtain方法
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 然后赋值到新Message中。

public static Message obtain(Handler h) {
        Message m = obtain();
        m.target = h;

        return m;
    }
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;
    }
recycle
/**
     * Return a Message instance to the global pool.
     * <p>
     * You MUST NOT touch the Message after calling this function because it has
     * effectively been freed.  It is an error to recycle a message that is currently
     * enqueued or that is in the process of being delivered to a Handler.
     * </p>
     */
    public void recycle() {
        if (isInUse()) {
            if (gCheckRecycle) {
                throw new IllegalStateException("This message cannot be recycled because it "
                        + "is still in use.");
            }
            return;
        }
        recycleUnchecked();
    }

将Message对象放在对象池中。调用此函数后,你就不能在�操作这个它了,因为它已经被释放了。

  • recycleUnchecked
 /**
     * Recycles a Message that may be in-use.
     * Used internally by the MessageQueue and Looper when disposing of queued Messages.
     */
    void recycleUnchecked() {
        // Mark the message as in use while it remains in the recycled object pool.
        // Clear out all other details.
        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++;
            }
        }
    }

回收可能正在使用的消息.
将消息标记成正在使用,并保留到回收池中
清除其它的字段。

/**
     * Make this message like o.  Performs a shallow copy of the data field.
     * Does not copy the linked list fields, nor the timestamp or
     * target/callback of the original 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;
        }
    }

复制一份Message

  • setAsynchronous
public void setAsynchronous(boolean async) {
        if (async) {
            flags |= FLAG_ASYNCHRONOUS;
        } else {
            flags &= ~FLAG_ASYNCHRONOUS;
        }
    }

设置Message是否是异步

    /*package*/ boolean isInUse() {
        return ((flags & FLAG_IN_USE) == FLAG_IN_USE);
    }

判断当前的Message的消息是否正在使用,FLAG_IN_USE =1 ,
(flags & 1) == 1,也就是只有flags=1时,或者flags==3时,为true,flags == 3时,是因为调用setAsynchronous(boolean)方法参数为true,异步的时候。flags== 1的情况就是,默认为0,释放资源赋值为1,

    /*package*/ void markInUse() {
        flags |= FLAG_IN_USE;
    }
其它

下面的就是Parcelable实现的方法。

public static final Parcelable.Creator<Message> CREATOR
            = new Parcelable.Creator<Message>() {
        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();
    }

总结

  1. 存放要发送的数据(when,what,obj,arg1,arg2,replyTo,target,data.....)
  2. 创建Message对象时,优先去回收池中拿,回收池中最大存储50个对象。
  3. 使用完毕释放资源,加入到回收池。
  4. 判断此消息是否正在使用中。
  5. 设置异步消息。
  6. 跨进程发送消息(Messenger类)
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。