Android源码handler机制之Message

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加锁:对象池是一个静态变量,操作方法也是静态方法,没必要在类上加锁

你可能感兴趣的:(Android源码handler机制之Message)