美文网首页Android技术知识Android开发Android精选
Message.obtain()中的单链表栈缓存

Message.obtain()中的单链表栈缓存

作者: HWilliamgo | 来源:发表于2019-01-16 17:21 被阅读3次

Message.obtain()中的单链表栈缓存

Android中的Message.java用单链表实现了一个size=50的栈,用作缓存。以下结合源码和图分析存取过程。

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) {
            next = sPool;
            sPool = this;
            sPoolSize++;
        }
    }
}

调用时机:在Looper.loop中调用,具体地说在Handler.handleMessage()之后立刻调用。

public void static loop(){
    final Looper me=Looper.myLopper();
    final MessageQueue queue = me.mQueue;
    for(;;){
        //...
        Message msg = queue.next();
        msg.target.dispatchMessage(msg);
        //上面的dispatchMessage最终执行到handler的handleMessasge了
        msg.recycleUnchecked();
    }
}

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

调用时机:这个应该由开发者在需要Message对象的时候手动调用来获取缓存池中的Message对象。

结合图来分析存取过程中单链表栈的变化

第一次存取

  1. 初始状态,sPool指向null。没有任何Messsage对象。
1547627128889.png
  1. 调用一次Message.obtain()。由于sPool==null,因此直接new Message()并返回给开发者使用,在用完后,Looper为其调用了 msg.recycleUnchecked();将其回收。

    synchronized (sPoolSync) {
        if (sPoolSize < MAX_POOL_SIZE) {
            next = sPool;//1
            sPool = this;//2
            sPoolSize++;//3
        }
    }
    

    开始分析,此时还未执行代码段1,2,3。

1547627414730.png

执行1。(此时Message1.next实际上指向了Null)


执行2。(sPool引用指向了对象Message1)


执行3。将缓存池数量标记+1。

第二次存取

  1. 初始状态
  1. 开发者调用Messsage.obatin()来获取Message对象

    public static Message obtain() {
        synchronized (sPoolSync) {
            if (sPool != null) {
                Message m = sPool;//1
                sPool = m.next;//2
                m.next = null;//3
                m.flags = 0; // clear in-use flag
                sPoolSize--;
                return m;//4
            }
        }
        return new Message();
    }
    

    执行1。(创建一个Message m引用,指向了sPool所指向的对象Message1)


    1547628442298.png

执行2。(让sPool指向null)


1547628468565.png

执行3。还是上面的原图

执行4。将引用m返回,交给开发者,其指向了对象Message1,开发者可以拿着这个引用对其做处理。

  1. 由Looper来调用msg.recycleUnchecked将其回收。其所有过程和第一次存取的回收过程如出一辙。

多次存取

  1. 一次性调用多次obtain,由于当缓存池中没有Message对象时,sPool指针就会==null,因此就会直接生成Message实例,如图:
1547628887922.png
  1. 此时每一个Message都被handler处理完成,并准备一个一个被Looper回收。

    执行Message1的回收:

1547628987637.png

执行Message2的回收:

1547629051003.png

执行Message3的回收


1547629167436.png

执行Message4的回收


1547629182292.png

如图,此时Message维护了一个单链表构成的栈,sPool指向栈顶

当obtainMessage()时,创建一个引用指向sPool,即指向栈顶的Message4,将sPool指向Message4.next即Message3,再将Message4.next=null,将Message4对象脱离单链!
表,最后将引用返回给开发者,供开发者操纵对象Message4。图不再给出。

相关文章

网友评论

    本文标题:Message.obtain()中的单链表栈缓存

    本文链接:https://www.haomeiwen.com/subject/nunmdqtx.html