欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Android基础之Handler机制(二)之Message源码分析

程序员文章站 2022-07-14 16:45:28
...

基于8.0.0源码

##定义##

Defines a message containing a description and arbitrary data object that can be sent to a {@link Handler}.  This object contains two extra int fields and an extra object field that allow you to not do allocations in many cases.

个人理解:

定义一个可以被发送到Handler的包含一个描述和任意类型数据对象的消息. 这个消息对象包含两个额外的int属性和一个额外的object属性可以让我们在大多情况下不需要做过多配置.

方法细节##

类实现

我们知道在Java中传输数据要实现序列化就是实现Serializable,Android中提倡使用Parcelable.
  • Message类实现了Parcelable接口
    • 重写describeContents()和writeToParcel(Parcel dest, int flags) 方法

###构造方法###

  • 空参的构造方法

  • 系统提示创建一个Message首选的方法应该是Message.obtain()方法.

  • 为什么要用obtain()方法呢?我们进源码看下

      /**
      * Return a new Message instance from the global pool. Allows us to
      * avoid allocating new objects in many cases.
      * 从缓存池中返回一个新的Message对象实例,让我们避免了在大多数情况下new一个新的对象
      */
      public static Message obtain() {
      	//上锁,同一时间只有一个线程能进入
      	synchronized (sPoolSync) {
      		//如果pool不为空,就说明缓存池中有对象
          	if (sPool != null) {
      			//把sPool的引用赋值给m
          	    Message m = sPool;
          	    sPool = m.next;
      			//m的next置为null
          	    m.next = null;
      			//清除Message的标记,不在in-use状态
          	    m.flags = 0; // clear in-use flag
          	    sPoolSize--;
          	    return m;
         		 }
      	}
      	//如果为空,则返回一个新的Message对象
      	return new Message();
      }
    

    其实就是内部维护了一个链表形式的Message对象缓存池

###保存数据的相关属性和方法###

  • int what

    • 用于辨别不同消息的标识属性
  • int arg1 ,int arg2

    • 简单整数型属性
  • Object obj

    • 我们开发可以自己定义的属性
  • Bundle data

    • 如果有其他数据,可以用bundle来传输
    • 把需要传输的数据用Bundle来封装,然后再调用msg的setData方法设置进去

obtain 方法

  • static Message obtain()

    • 空参方法,一般用来创建Message
  • static Message obtain(Message orig)

    • 传入msg参数
    • 把传入orig中的数据拷贝到一个新的Msg对象中, 返回的这个新的对象是从Msg的缓存池中获取的.
  • static Message obtain(Handler h)

    • 传入Handler 参数
    • 从Msg的缓存池中返回一个Msg对象,并且把该Msg对象的target属性的引用指向 入参handler,这样该Msg就持有了Handler的引用
  • static Message obtain(Handler h, Runnable callback)

    • 传入Handler参数,Runnable 参数
    • 当Loop分发消息时,如果callback不为空,那么这个Runnable对象就不会调用Handler的handlerMessage方法.而是在已经回到创建Handler的那个线程上运行Runnable对象.
  • static Message obtain(Handler h, int what)

    • 传入 Handler,消息标识 what
    • 把从缓存池中返回的Msg的属性target和what的引用指向这两个参数
  • static Message obtain(Handler h, int what, Object obj)

    • 传入 Handler,消息标识 what,自定义obj
    • 把从缓存池中返回的Msg的属性target和what和obj的引用指向这三个参数
  • static Message obtain(Handler h, int what, int arg1, int arg2)

    • 同上解释,参数赋值
  • static Message obtain(Handler h, int what,
    int arg1, int arg2, Object obj)

    • 同上解释,参数赋值

缓存池回收方法

  • void recycle()

      //往缓存池中添加一个Msg实例,
      public void recycle() {
      	//判断Msg是否在使用
      	if (isInUse()) {
      		//这里的gCheckRecycle标识位是指是否大于5.0版本,大于的话是true,小于的话是false
          	if (gCheckRecycle) {
              	throw new IllegalStateException("This message cannot be recycled because it "
                      + "is still in use.");
          	}
          	return;
      	}
      	recycleUnchecked();
      }
    
  • 最终调用 recycleUnchecked()

      //回收一个可能正在被使用的Msg,MessageQueue和Looper都会调用这个方法去回收Msg
      void recycleUnchecked() {
      	// Mark the message as in use while it remains in the recycled object pool.
      	// Clear out all other details. 归零Msg所有属性
      	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++;
          	}
      	}
      }
    

Msg异步传输/同步传输

  • boolean isAsynchronous()

    • 判断Msg是否是异步传输,如果是异步传输就返回true
  • void setAsynchronous(boolean async)

    • 设置Msg是否为异步传输
    • 如果设置成异步传输,Msg在MessageQueue中的位置可能被打乱,Msg对象将不受Looper控制,请小心使用
相关标签: Message源码