> 文档中心 > Message享元模式学习

Message享元模式学习

android是如何对Message进行复用的

  • java的类是由成员变量+构造函数+成员方法组成->先看成员变量
  • 一开始的获取Message对象
  • 如何回收
    • 第一次进来
    • 第二次进来
    • 第三次进来
  • 回过头来我们再看获取message
  • 到了这里想必大家都明白它的核心是什么了吧?

java的类是由成员变量+构造函数+成员方法组成->先看成员变量

涉及复用的关键成员变量有:
Message next;
private static Message sPool;
private static int sPoolSize = 0;
private static final int MAX_POOL_SIZE = 50;

一开始的获取Message对象

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

synchronized :这个就不在这里解释了,太基础,有兴趣的同学可以看下我之前写的并发编程里面有对应的解释。
if (sPool != null):这个判断第一次肯定是进不去的,全局搜索了一下,只有在回收的地方有赋值,所以它一直是null,那么开始的时候肯定都是直接new的方法去创建的,而且在实际过程中,可能一开始就new了很多个对象出来,因为message要等用完才会开始回收,所以一开始获取的Message都是直接new。

如何回收

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

第一次进来

if (sPoolSize < MAX_POOL_SIZE) :只要复用池里面的对象还没满,就可以往里面继续加,因为我们是强引用持有,回收不了的,所以定义的最大数量要合适,这里系统定义的是最大值是50
next = sPool :第一次进来两个都是null
sPool = this :给sPool赋值,第一个用完的对象进行强应用持有,不会被回收。
sPoolSize++:统计上+1
在这里插入图片描述

第二次进来

next = sPool :sPool是上一个回收对象message1,赋值给next,注意sPool是静态。
sPool = this :给sPool赋值,第二个用完的对象进行强应用持有,不会被回收。
sPoolSize++:统计上+1,注意sPoolSize是静态。
在这里插入图片描述

第三次进来

next = sPool :sPool是上一个回收对象message2,赋值给next
sPool = this :给sPool赋值,第三个用完的对象进行强应用持有,不会被回收。
sPoolSize++:统计上+1

到了此刻,这个链表的结构应该在你的脑海中能够想象出来了。

回过头来我们再看获取message

 if (sPool != null) {  Message m = sPool;  sPool = m.next;  m.next = null;  m.flags = 0; // clear in-use flag  sPoolSize--;  return m;     }

当复用池中存在对象的时候,sPool不为空,该判断可以进去。
Message m = sPool; //创建了一个局部对象m并赋值,可以想象成上面的message3
sPool = m.next;//把m的next对象从原来的指向message2指向自己,也就是message3
m.next = null;//把message3指向自己message3的强引用断开
m.flags = 0; // clear in-use flag ,是一个标志位,是否在使用中。
sPoolSize–;//计数减1
return m //把m对象返回给使用者使用。
经过上面的代码之后,message3指向message2的强引用没有了,对象又重新进行了使用,计数器减1.

到了这里想必大家都明白它的核心是什么了吧?

我一开始没注意直接看了复用和回收的方法,怎么都想不明白,然后第二天上班突然看到了:
private static Message sPool;
private static int sPoolSize = 0;
private static final int MAX_POOL_SIZE = 50;
就一个关键:static
好了,到了这里message的复用逻辑已经很清晰明确了,如果大家有什么问题,欢迎在评论区留言讨论。