Handler的前世今生3——Message

1. Message的重要属性

Message文档

Each Handler has its own name-space for message codes, so you do not need to worry about yours conflicting with other handlers. 每个Handler都有自己命名空间的消息码,这样不必担心和其它Handler冲突。

每个Handler只处理自家的Message, 但Message是如何区分Handler呢?

这就需要我们考虑去将MessageHandler 进行绑定。

我们查看Message的源码,会发现有一个成员变量:

Handler target;

当我们查看Message中各个obtain()方法,都会发现与target进行绑定(特殊的obtain()可以进一步查看Handler,其最终也是要对target进行绑定的,这里不再展开)。

 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;
    }

除了target ,还有:

Runnable callback

public long when;

关于Handler的更多详情 Handler的前世今生4——Handler


2. Message 的obtain()

官方建议我们在发送消息尽量使用obtain(),我们来看一下obtain()的实现:

从全局的消息池中给我们返回一个新的Message实例,很多情况下可以避免我们新建对象。

 /**
     * 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();

我们通过进一步的分析Message的成员变量:

Message next;
private static Message sPool;
public static final Object sPoolSync = new Object(); // 全局锁对象
private static int sPoolSize = 0;
private static final int MAX_POOL_SIZE = 50;

这就告诉我们,Message是链表设计Message池的最大数量为50.


3. Message的回收

FLAG_IN_USE 标记消息在使用中,当消息进入队列或者复用时都被被置为该状态。

 /** If set message is in use.
     * This flag is set when the message is enqueued and remains set while it
     * is delivered and afterwards when it is recycled.  The flag is only cleared
     * when a new message is created or obtained since that is the only time that
     * applications are allowed to modify the contents of the message.
     *
     * It is an error to attempt to enqueue or recycle a message that is already in use.
     */
    static final int FLAG_IN_USE = 1 << 0;

recyclerUnchecked()方法是用来复用消息的。这里主要就是对消息的属性恢复默认,其判断消息池是否溢出。我们在Looper的loop()方法看过它的身影。

 /**
     * Recycles a Message that may be in-use.
     * Used internally by the MessageQueue and Looper when disposing of queued Messages.
     */
    @UnsupportedAppUsage
    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 = UID_NONE;
        workSourceUid = UID_NONE;
        when = 0;
        target = null;
        callback = null;
        data = null;

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

我们还看到一个recycle() 方法:

 public void recycle() {
        if (isInUse()) {
            if (gCheckRecycle) {
                throw new IllegalStateException("This message cannot be recycled because it "
                        + "is still in use.");
            }
            return;
        }
        recycleUnchecked();
    }

有没有似曾相识的感觉,你在处理Bitmap时…(PS:Bitmap类中也有一个recycle()方法)。在涉及到复用的情况下,基本都会出现该方法的身影。

为什么Looper的loop()方法调用的是recycleUnchecked()呢?

个人认为是:loop()中可以保证消息一定没有在使用,完全没有必要判断isInUse(),所以直接调用了recycleUnchecked()。

OK ,关于Message的内容就介绍到这里…

欢迎继续收看 Handler的前世今生4 —— Handler

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章