查看原文
其他

Handler消息机制完全解析(一)Message中obtain()与recycle()的来龙去脉

2017-06-20 -_-void 终端研发部


前言介绍

Handle运行机制的完全解析之Message中obtain()与recycle()的来龙去脉

博客地址:

http://blog.csdn.net/xmh19936688/article/details/51901338

正文
  • Android自助餐Handler消息机制完全解析一Message中obtain与recycle的来龙去脉

    • 提供obtain

    • 回收recycle

提供obtain()

在obtain的所有重载方法中,第一行都是Message m = obtain();,即调用空参的方法。 
先来看一下这个空参方法

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


很明显,这是个同步方法:

  • sPoolSync 即锁对象

  • 该对象在定义时即被初始化private static final Object sPoolSync = new Object();

  • 随后便只读不写。

  • 然后便是sPool,后面还有Message m = sPool;sPool = m.next;

  • 很明显可以看出来,这是一个链表结构。sPool指向当前message,next指向下一个message。

在解释这段代码前,需要先明确两点:

  • sPool声明为private static Message sPool;;next声明为/package/ Message next;。

  • 即前者为该类所有示例共享, 后者则每个实例都有。

现在为了便于理解,我们将Message抽象为C语言中的链表节点结构体,指针域便是用于指向下一个消息的next字段,其他则都视为数据域。

假设该链表初始状态如下


 
执行Message m = sPool;就变成下图 


 
继续sPool = m.next;

 
 
然后m.next = null; 


 
接下来m.flags=0;sPoolSize--;return m;便是表示m指向的对象已经从链表中取出并返回了。

回收recycle()

然后再看看sPoolSize是什么时候自增的。按图索骥便可找到recycle()方法和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 = -1;    when = 0;    target = null;    callback = null;    data = null;    synchronized (sPoolSync) {      
if (sPoolSize < MAX_POOL_SIZE) {            next = sPool;            sPool = this;            sPoolSize++;        }    } }

前半段不必多说,显然是“重置”改对象的个个字段。后半段又是一个同步代码段,同样用图来解释一下(假设当前代码为message.recycle(),则需要被回收的则是message对象)。 
假设当前链表如下: 


 

执行next=sPool; 




执行sPool=this



现在可以很清楚的看到,Message类本身就组织了一个栈结构的缓冲池。并使用obtain()方法和recycler()方法来取出和放入。

补充:

在handler.obtainMessage()的参数是这样写的:

Message android.os.Handler.obtainMessage(int what, int arg1, int arg2, Object obj)public final Message obtainMessage (int what, int arg1, int arg2, Object obj) Since: API Level 1Same as obtainMessage(), except that it also sets the what, obj, arg1,and arg2 values on the returned Message. Parameters what Value to assign to the returned Message.what field. arg1 Value to assign to the returned Message.arg1 field. arg2 Value to assign to the returned Message.arg2 field. obj Value to assign to the returned Message.obj field.

而Handler中obtainMessage与new Message的区别:

  • obtainmessage()是从消息池中拿来一个msg 不需要另开辟空间

  • new需要重新申请,效率低,obtianmessage可以循环利用;

源码中是这样说的:

//use Handler.obtainMessage(),instead of msg = new Message();//because if there is already an Message object,that not be used by //any one ,the system will hand use that object,so you don’t have to//create and object and allocate memory. //it is also another example of object recycling and reusing in android. Message msg = mHandler.obtainMessage();msg.what = UPDATE_LISTVIEW; msg.obj = current + “/“ + total + “songs”; //this method is called from worker Thread,so we cannot update UI from here. msg.sendToTarget();

在看下面代码:

Message msg = handler.obtainMessage();

msg.arg1 = i;msg.sendToTarget();

Message msg=new Message();msg.arg1=i;

handler.sendMessage(msg);

总结

  • 第一种写法是message 从handler 类获取,从而可以直接向该handler 对象发送消息

  • 第二种写法是直接调用 handler 的发送消息方法发送消息。

相关博客地址:

http://blog.csdn.net/xmh19936688/article/details/51901338


让心,在阳光下学会舞蹈

让灵魂,在痛苦中学会微笑

—终端研发部—



如果你觉得此文对您有所帮助,欢迎入群 QQ交流群 :232203809   

微信公众号:终端研发部



            

这里学到的不仅仅是技术





您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存