Android开发Android开发经验谈Android技术知识

回转寿司你一定吃过!——Android消息机制(构造)

2019-02-01  本文已影响9人  唐子玄

消息机制的故事


  • 寿司陈放在寿司碟上,寿司碟按先后顺序被排成队列送上传送带传送带被启动后,寿司挨个呈现到你面前,你可以选择吃或者不吃。

将Android概念带入后,就变成了Android消息机制的故事:
寿司碟 ---> 消息(Message)
队列 ---> 消息队列(MessageQueue)
传送带 ---> 消息泵 (Looper)
寿司 ---> 你关心的数据

暂未找到 Handler 在此场景中对应的实体。它是一个更抽象的概念,它即可以生产寿司,又把寿司送上传送带,还定义了怎么享用寿司。暂且称它为消息处理器吧。

如果打算自己开一家回转寿司店,下面的问题很关键:

  1. 如何生产寿司(如何构造消息)
  2. 如何分发寿司(如何分发消息)

让我们带着这两个问题,去分析一下消息机制源码。
(ps: 下文中的 粗斜体字 表示引导源码阅读的内心戏)

如何构造消息


寿司碟是重复利用的,享用完寿司后,它被清洗,然后被存放起来,以便再次利用。没有哪个老板会在用餐后把寿司碟销毁,下次要用就买新的,这样代价太大。
同样道理,构造消息对象代价也很大,它是否也像寿司碟一样可以复用?如果是,那消息存放在哪里?
让我们以Handler.obtainMessage()为切入点一探究竟:

 public final Message obtainMessage(){
     return Message.obtain(this);
 }

它调用了Message.obtain(),源码如下:

public final class Message implements Parcelable {
    //省略了非关键代码
    ...
    // sometimes we store linked lists of these things
    //指向消息链上下一个消息的引用
    /*package*/ Message next;

    //消息链头部引用,它是静态的,可以被所有消息对象共享
    private static Message sPool;
    //消息链长度
    private static int sPoolSize = 0;

    ...
    /**
     * 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) {
                //1. 定义指向消息链头部引用
                Message m = sPool;
                //2. 定义新的消息链头部
                sPool = m.next;
                //3. 断链
                m.next = null;
                m.flags = 0; // clear in-use flag
                sPoolSize--;
                //返回消息链头部消息
                return m;
            }
        }
        //如果消息链为空则新建消息
        return new Message();
    }
    ...
}
2 3
    /**
     * 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) {
                //1. 回收的消息接入消息链
                next = sPool;
                //2. 回收的消息成为消息链新头部
                sPool = this;
                sPoolSize++;
            }
        }
    }
2

总结


Android消息机制中的“构造消息”部分讲完了,总结一下:消息的生命周期会经历“创建-回收-再利用”,所有消息共享一个链表结构的消息池,它用于存放被回收的消息。

故事还没有结束,下一篇会继续讲解“分发消息”。

上一篇下一篇

猜你喜欢

热点阅读