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); }
getMap(t)方法的执行
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基本上已经介绍完毕ÿ