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

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加锁:对象池是一个静态变量,操作方法也是静态方法,没必要在类上加锁
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,425评论 4 361
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,058评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,186评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,848评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,249评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,554评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,830评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,536评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,239评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,505评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,004评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,346评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,999评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,060评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,821评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,574评论 2 271
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,480评论 2 267

推荐阅读更多精彩内容