Handler之Message分析

创建Message的3中方式:

第一种方式:

//这种是常见的创建对象的方式,每次需要发送消息的时候都需要创建一个Message 对象,每次都要到堆内存中开辟新的存储空间,使用之后jvm再次进行回收处理
Message message = new Message();

第二种方式:

Message message = mHandler.obtainMessage();

先简单看下源码,发现其实实现的原理也是方式三,调用的是obtain()方法,所以下面着重分析obtain方法: 
public final Message obtainMessage(){
    return Message.obtain(this);
}

public static Message obtain(Handler h) {
    Message m = obtain();
    m.target = h;
    return m;
}

第三种方式:

 Message message = Message.obtain();

这两种方式实质上是一样的,都会有一个单链表缓存池来缓存创建的消息,如果缓存池中没有message,会创建一个新的message,如果缓存池中含有消息,则拿出来使用

Message中携带的信息

/**
 * 用来区别handler发出的消息的类型
 */ 
 public int what;
/**
 * arg1 和 arg2是定义了两个整形数据,数据少的话直接用这两个即可
 */
 public int arg1;

 public int arg2;
/**
 * 发送给接受方的任意对象,在使用跨进程的时候要注意obj不能为null
 */
 public Object obj;
/**
 * 在使用跨进程通信Messenger时,可以确定需要谁来接收
 */
 public Messenger replyTo;
/**
 * 在使用跨进程通信Messenger时,可以确定需要发消息的uid
 */
 public int sendingUid = -1;
/**
 * 如果数据比较多,可以直接使用Bundle进行数据的传递
 */
 Bundle data;

测试代码:

Message message = Message.obtain();
message.what = 0xff;
//int 
message.arg1 = 100;
//obj
message.obj = new Student("赵日天");
//bundle
Bundle bundle = new Bundle();
bundle.putString("name", "赵日天");
bundle.putInt("age", 18);
message.setData(bundle);
//发送消息
mHandler.sendMessage(message);
 public class Student {
        private String name;

        public Student(String name) {
            this.name = name;
        }

        public String getName() {
            return name;
        }
    }
 private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            Log.i("msg", "handleMessage: " + msg.what);
            if (msg.what == 0xff) {
                Log.i("msg", "handleMessage: " + msg.arg1);
                Student student = (Student) msg.obj;
                Log.i("msg", "handleMessage: " + student.getName());
                Bundle bundle = msg.getData();
                Log.i("msg", "handleMessage: " + bundle.getString("name") + " age  :" + bundle.getInt("age"));
            }
        }
    };

输出日志

06-19 04:00:06.283 2594-2594/? I/msg: handleMessage: 255
06-19 04:00:06.283 2594-2594/? I/msg: handleMessage: 100
06-19 04:00:06.283 2594-2594/? I/msg: handleMessage: 赵日天
06-19 04:00:06.283 2594-2594/? I/msg: handleMessage: 赵日天 age  :18

源码分析:

源码: 我们发现如果消息池sPool不为空的话,会从里面取出一个消息实现复用,如果为空的话,先new一个消息
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();
}

public Message() {
}

上面的方法里面相关的变量介绍:

    sPoolSync 主要的目的是给Message加一个对象锁,防止多线程同时访问Message类和obtain方法,导致取出的消息发生错误
    public static final Object sPoolSync = new Object();
    sPool 主要是存储我们循环利用的Message单链表,这里的sPool 值得是链表的头结点
    private static Message sPool;
    单链表的链表的长度,即存储的Message对象的个数。
    private static int sPoolSize = 0;

分析obtain:
假设消息池中含有三个消息:sPool为下图表示的样子:
在这里插入图片描述
1 :Message m = sPool
在这里插入图片描述2 sPool = m.next;
在这里插入图片描述3:m.next = null;
在这里插入图片描述这时我们从上面的图中可以发现已经取出了一个消息m,并且sPool链表中的消息数量sPoolSize也由3个变为了两个,即 sPoolSize–,

recycle以及recycleUnchecked

void recycleUnchecked() {
    // Mark the message as in use while it remains in the recycled object pool.
    // Clear out all other details.
    //这段代码主要是重置message的一些变量,以便重复使用
    flags = FLAG_IN_USE;
    what = 0;
    arg1 = 0;
    arg2 = 0;
    obj = null;
    replyTo = null;
    sendingUid = -1;
    when = 0;
    target = null;
    callback = null;
    data = null;

    //这个主要是把上面使用的重置过的message添加到sPool中以便重复利用
    synchronized (sPoolSync) {
        if (sPoolSize < MAX_POOL_SIZE) {
            next = sPool;
            sPool = this;
            sPoolSize++;
        }
    }
}

在这里插入图片描述
在这里插入图片描述在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值