源码分析 Handler 机制(三) —— Message

本文基于 SDK-33

主要成员属性

  • int what:消息的身份标识
  • int arg1 和 int arg2:用于存储简单的 int 类型数据
  • Object obj:用于存储复杂的对象数据
  • Messenger replyTo:用于跨进程通信
  • long when:用于标识 Message 什么时候执行
  • Handler target:标识该消息由哪个 Handler 处理
  • Runnable callback:存储通过 Handler.postXXX 传入的 Runnable 对象
  • Message next:指向 MessageQueue 中存储的下一个 Message
  • Message sPool:消息池中的头部消息
  • int sPoolSize:消息池中消息数量
  • int MAX_POOL_SIZE:消息池最大消息数量

创建消息

构造方法

    public Message() {
    }

该方法会直接创建一个 Message 对象,但不推荐使用。

obtain 方法

该方法会在消息池中返回一个 Message 对象,如果消息池中为空,才会创建新对象

    public static Message obtain() {
        synchronized (sPoolSync) {//因为可能在不同线程中调用该方法创建 Message 对象,所以需要加锁保证线程安全
            if (sPool != null) {//消息池头部不为null,表示消息池不为空
                Message m = sPool;//获取池头消息
                sPool = m.next;//将第二个消息标记为池头
                m.next = null;//将原池头消息中标识的下一个消息清空
                m.flags = 0; //将原池头消息的标记清零
                sPoolSize--;//池中消息数量 -1
                return m;//返回消息
            }
        }
        return new 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;
        m.workSourceUid = orig.workSourceUid;
        if (orig.data != null) {
            m.data = new Bundle(orig.data);
        }
        m.target = orig.target;
        m.callback = orig.callback;

        return m;
    }

    //指定消息的 target
    public static Message obtain(Handler h) {
        Message m = obtain();
        m.target = h;

        return m;
    }

    //指定消息的 target 和 callback
    public static Message obtain(Handler h, Runnable callback) {
        Message m = obtain();
        m.target = h;
        m.callback = callback;

        return m;
    }

    //指定消息的 target 和 what
    public static Message obtain(Handler h, int what) {
        Message m = obtain();
        m.target = h;
        m.what = what;

        return m;
    }

    //指定消息的 target 和 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;
    }

    //指定消息的 target 和 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;
    }

    //指定消息的 target 和 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 void recycle() {
        if (isInUse()) {//如果消息正在使用中
            if (gCheckRecycle) {//如果设置了回收检测,则抛出异常,如果没有设置回收检测,则直接返回,不进行回收
                throw new IllegalStateException("This message cannot be recycled because it "
                        + "is still in use.");
            }
            return;
        }
        recycleUnchecked();//如果没有正在使用,则进行回收
    }

    /**
     * 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;//设置消息 flag
        what = 0;//清除 Message 的各种属性
        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;//将原池内头部消息的next 指向原消息头
                sPool = this;//将回收的消息作为消息头
                sPoolSize++;//池内消息数量 +1
            }
        }
    }

同步/异步消息

    static final int FLAG_ASYNCHRONOUS = 1 << 1;    

    public boolean isAsynchronous() {
        return (flags & FLAG_ASYNCHRONOUS) != 0;
    }

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

可以通过 setAsynchronous(true) 将消息设置为异步消息。如果消息是异步消息,则 isAsynchronous() 方法会返回 true。

异步消息主要和同步消息屏障配合使用,在 MessageQueue 源码分析中有讲解。

Copyright© 2020-2022 li-xyz 冀ICP备2022001112号-1