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

消息机制的故事寿司陈放在寿司碟上,寿司碟按先后顺序被排成队列送上传送带。传送带被启动后,寿司挨个呈现到你面前,你有三种享用寿司的方法。

将Android概念带入后,就变成了Android消息机制的故事:

寿司碟 ---> 消息(Message)

队列 ---> 消息队列(MessageQueue)

传送带 ---> 消息泵 (Looper)

寿司 ---> 你关心的数据

享用寿司方法 ---> 处理数据方式

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

如果打算自己开一家回转寿司店,下面的问题很关键:如何生产寿司(如何构造消息)

如何分发寿司(如何分发消息)

让我们带着这两个问题,去分析一下消息机制源码。

(ps: 下文中的 粗斜体字 表示引导源码阅读的内心戏)

如何构造消息

寿司碟是重复利用的,享用完寿司后,它被清洗,然后被存放起来,以便再次利用。没有哪个老板会在用餐后把寿司碟销毁,下次要用就买新的,这样代价太大。

同样道理,构造消息对象代价也很大,它是否也像寿司碟一样可以复用?如果是,那消息存放在哪里?

让我们以Handler.obtainMessage()为切入点一探究竟:public class Handler {

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

}

...

}public final class Message implements Parcelable {

...  /**

* Same as {@link #obtain()}, but sets the value for the target member on the Message returned.

* @param h  Handler to assign to the returned Message object's target member.

* @return A Message object from the global pool.

*/

public static Message obtain(Handler h) {

Message m = obtain();

m.target = h;     return m;

}

...

}其中Message.target是一个Handler类型的成员变量。为啥Message要记录构造它的Handler对象? 好问题!但这个问题的解答需要等到分析消息处理的时候才能解答,先留个悬念。

构造消息调用链的终点是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();

}

...

}如果对数据结构中的链表还有映像,obtain()就是在取链表头。图示如下:

AAffA0nNPuCLAAAAAElFTkSuQmCC

1

AAffA0nNPuCLAAAAAElFTkSuQmCC

2

AAffA0nNPuCLAAAAAElFTkSuQmCC

3消息池是用链表结构实现的。那 Message一定有一个指向后续结点的“指针”,果不其然,在其成员变量中找到Message next;。

消息池头指针sPool是一个Message类型的静态变量,这表示所有Message都共享这一个消息池。

obtain()是从消息池中拿消息,那一定还有一个方法是往池里填消息,在Message类中搜索sPool使用的地方,找到如下这个方法:/**

* 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 

next = sPool;                //2. 回收的消息成为消息链新头部

sPool = this;

sPoolSize++;

}

}

}正如猜想的那样recycleUnchecked()会将当前消息插入到消息链头部。图示如下

AAffA0nNPuCLAAAAAElFTkSuQmCC

1

AAffA0nNPuCLAAAAAElFTkSuQmCC

AAffA0nNPuCLAAAAAElFTkSuQmCC

2读到这里,我们知道“消息从池中来最终又回到池中去”,那到底消息是在什么时候才会被回收到消息池呢? 好问题!这个问题要等分析完消息分发才能解答。但现在我们可以大胆的猜测一下:承载寿司的碟子会在寿司被享用完之后被厨房回收,那消息是不是再被处理完之后就被回收了?

作者:唐子玄

链接:https://www.jianshu.com/p/134986dfe61b

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值