Android消息通信机制Handler详解,Handler,Looper,MessageQueue,源码解析,讲解这几个类怎么配合工作的

                                                             android的消息机制Handler

 




 

 

说到Handler大家都不陌生,我们在平常会经常使用,Handler就是子线程和UI线程(ActivityThread)进行通信,还有就是当我们做I/O操作时(数据库操作,访问网络)这些耗时操作android规定不能再主线程执行(开辟子线程在子线程执行),否则主线程5S内无响应会导致ANR的出现,当我们在子线程

访问网络获取到数据后,想展示在控件上这时Handler的价值就体现出来了。

 

 

 

那么为什么android规定不能再子线程更新UI呢?因为android的Ui控件不是线程安全的,当多个线程并发的访问UI控件的话,会发生一些意想不到的后果,

如果Ui控件加上线程安全会使Ui控件这一块的逻辑异常复杂,降低UI的访问效率

 

android中使用Handler得有MessageQueue,Looper的支撑,

MessageQueue就是消息队列,内部的存储结构是单链表的形势,用于存储Handler发送过来的消息对外提供删除和插入数据的工作,MessageQueue只是用于存储数据, 而不能够处理数据,这时Looper的价值就体现出来了,其实Looper的工作就是通过调用Looper.loop()会是进入一个无限循环的状态每到MessageQueue有数据就将其取出,没有就处于等待状态,在Looper中实例化一个成员,那就是ThreadLocal,它并不是线程,它的作用是存储每个线程中的数据,Handler获取当前线程的Looper就是通过ThreadLocal来获取的,下面将通过一个一个类来给大家进行介绍,然后再在把Handler执行过程中的类串联起来,讲解一下Handler的执行过程,以及涉及到的类是怎么配合工作的。

 

ThreadLocal:(线程局部变量)
ThreadLocal<>,其实它是一个泛型类,而不是一个线程,那么此类的作用,官方也给详细的解释,TreadLocal类,是存储数据用的,它存储的数据是有局限性的,它仅限于存储线程内部的数据(比如:线程创建Looper),它能指定线程存储数据,也能指定线程取出数据,各线程之间互不干扰,它提供了2个方法,一个set(),一个get()当我们调用set()方法时,它会获取你当前的线程,刚才已经说到ThreadLocal<>它仅限于存储线程内部的数据,其实在获取到的当前线程内部有一个成员变量是,ThreadLocal.ThreadLocalMap threadLocals = null;
ThreadLocalMap是ThreadLocal的一个内部类,就是封装我们存入的数据,大家可以看到它的默认值是null,就是当我们set()时,
set()的源码如下:
 
public void set(T value) {
    //当使用set方法时它会得到set()时的当前线程, //每个当前线程的内部都有一个ThreadLocal.ThreadLocalMap threadLocals = null,用于保存当前线程的ThreadLocalMap
    Thread t = Thread.currentThread();
      //返回当前线程的ThreadLocalMap数据
    ThreadLocalMap map = getMap(t);
    //如果查询出当前线程的存在,会把要保存的数据保存当前线程的ThreadLocalMap中,比如:Looper,因为下次取数据的时候,要根据线程ThreadLocalMap取出Looper
       if (map != null)
        //存入数据及当前ThreadLocal的索引
        map.set(this, value);
    else
        //如果当前线程ThreadLocalMap不存在,就会给当前线程初始ThreadLocalMap    createMap(t, value);
}
 
getMapt)方法的执行
ThreadLocalMap getMap(Thread t) {
    //返回当前线程的ThreadLocalMap数据
    return t.threadLocals;
}
 
createMap(t, value);方法的执行
//如果当前线程ThreadLocalMap不存在,就会给当前线程初始化ThreadLocalMap
void createMap(Thread t, T firstValue) {
    //参数1,代表当前的ThreadLocal,参数2代表要存入的数据
    t.threadLocals = new ThreadLocalMap(this, firstValue);
}
 
以上代码执行做到了它能指定线程存储数据,下面在介绍一下get()
 
通过代码可以看到get()也可以指定线程取出数据
public T get() {
    Thread t = Thread.currentThread();
    //从当前线程中ThreadLocalMap数据
    ThreadLocalMap map = getMap(t);
    //判断当前线程中ThreadLocalMap数据
    if (map != null) {
        //根据当前ThreadLocal的索引值查询对应的value
        ThreadLocalMap.Entry e = map.getEntry(this);
        if (e != null) {
            @SuppressWarnings("unchecked")
            T result = (T) e.value;
            return result;
        }
    }

    //返回初始值null
    return setInitialValue();
}
 
 
ThreadLocal基本上已经介绍完毕ÿ
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值