1.handler基本信息:
定义:一套 Android 消息传递机制。
作用:在多线程的应用场景中,将工作线程中需更新UI的操作信息 传递到 UI主线程,从而实现 工作线程对UI的更新处理,最终实现异步消息的处理。
使用Handler的原因:将工作线程需操作UI的消息 传递到主线程,使得主线程可根据工作线程的需求 更新UI,从而避免线程操作不安全的问题。
消息(Message):
定义:线程间通讯的数据单元(即Handler接收&处理的消息对象)
作用:存储需操作的通信信息
消息队列(Message Queue):
定义:一种数据结构(存储特点:先进先出)
作用:存储Handler发送过来的消息(Message)
处理者(handler):
定义:主线程与子线程的通信媒介 线程消息的主要处理者
作用:添加消息(Message)到消息队列(message Queue)处理循环器(Looper)分派过来的消息(message)
循环器(Looper):
定义:消息队列(Message Queue)与处理者(Handler)的通信媒介
作用:消息循环,即消息获取:循环取出消息队列(Message Queue)的消息(message)消息分发:将取出的消息(Message)发送给对应的处理者(Handler)
2..Handler使用方式 因发送消息到消息队列的方式不同而不同
共分为2种:使用Handler.sendMessage()、使用Handler.post()
2原理
通过handler.sendMessage这个方法,把当前的消息对象message传入到handler中,通过handler中的messagequeue对象的引用(通过在handler的构造函数中,用looper获取到的),把Message放入到MessageQueue中。在message存放的时候,message对象的target属性记录了当前的handler。message通过消息的执行时间when,从小到大排列插入到消息链表中。我们looper的loop方法中的for(死循环)去查看当前的MessageQueue链表中是否有需要执行的Message。通过Message的when(消息的执行时间判断)和当前的系统时间戳做对比,如果当前的系统时间戳小于当前messagequeue链表中的消息执行时间,当前的执行进入等待状态。(管道机制,nativepollonce)如果当前的系统时间戳大于或等于当前的MessageQueue链表中的消息执行时间,我们就把当前的message从消息链表中删除,并且把该消息返回给Looper的loop方法中。在loop方法中获取到message以后判断message所对应的target(也就是发送message的handler)是否存在,如果存在就调用target.dispathMessage方法把当前的message
传入,在dispathMessage方法中,我们将调用handleMessage这个方法。把当前取出的message传出去。这样在我们handler中重写的handleMessage就拿到了当前处理的消息。
4.Handler机制的工作流程主要包括4个步骤:
(1).异步通信准备:
具体描述:在主线程中创建:处理器对象(Looper)消息队列 对象(Message Queue)Handler 对象
(2).消息发送
具体描述:工作线程通过Handler发送消息(Message)到消息队列(Message Queue)中
(3).消息循环
具体描述:消息出队:Looper循环取出消息队列(Message Queue)中的消息(Message)消息分发:Looper将取出的消息(Message)发送给创建消息的处理着(Handler)
(4).消息处理
具体描述:处理者(Handler)接收处理器(Looper)发送过来的消息(Message)处理者(Handler)根据消息(Message)进行UI操作
5.当创建Handler对象时,则通过 构造方法 自动关联当前线程的Looper对象 & 对应的消息队列对象(MessageQueue),从而 自动绑定了 实现创建Handler对象操作的线程
创建主线程时,会自动调用ActivityThread的1个静态的main();而main()内则会调用Looper.prepareMainLooper()为主线程生成1个Looper对象,同时也会生成其对应的MessageQueue对象
即 主线程的Looper对象自动生成,不需手动生成;而子线程的Looper对象则需手动通过Looper.prepare()创建
6.在子线程若不手动创建Looper对象 则无法生成Handler对象
根据Handler的作用(在主线程更新UI),故Handler实例的创建场景 主要在主线程
消息循环的操作 = 消息出队 + 分发给对应的Handler实例
分发给对应的Handler的过程:根据出队消息的归属者通过dispatchMessage(msg)进行分发,最终回调复写的handleMessage(Message msg),从而实现 消息处理 的操作
特别注意:在进行消息分发时(dispatchMessage(msg)),会进行1次发送方式的判断:
若msg.callback属性不为空,则代表使用了post(Runnable r)发送消息,则直接回调Runnable对象里复写的run()
若msg.callback属性为空,则代表使用了sendMessage(Message msg)发送消息,则回调复写的handleMessage(msg)
7.线程安全就是多线程访问时,采用了加锁机制,当一个线程访问该类的某个数据时,进行保护,其他线程不能进行访问直到该线程读取完,其他线程才可使用。不会出现数据不一致或者数据污染。 线程不安全就是不提供数据访问保护,有可能出现多个线程先后更改数据造成所得到的数据是脏数据。
8.ThreadLocal提供了线程内存储变量的能力,这些变量不同之处在于每一个线程读取的变量是对应的互相独立的。通过get和set方法就可以得到当前线程对应的值。
ThreadLocal的静态内部类ThreadLocalMap为每个Thread都维护了一个数组table,ThreadLocal确定了一个数组下标,而这个下标就是value存储的对应位置。。
ThreadLocal是解决线程安全问题一个很好的思路,它通过为每个线程提供一个独立的变量副本解决了变量并发访问的冲突问题。在很多情况下,ThreadLocal比直接使用synchronized同步机制解决线程安全问题更简单,更方便,且结果程序拥有更高的并发性。
在每个线程Thread内部有一个ThreadLocal.ThreadLocalMap类型的成员变量threadLocals,这个threadLocals就是用来存储实际的变量副本的,键值为当前ThreadLocal变量,value为变量副本(即T类型的变量)。 初始时,在Thread里面,threadLocals为空,当通过ThreadLocal变量调用get()方法或者set()方法,就会对Thread类中的threadLocals进行初始化,并且以当前ThreadLocal变量为键值,以ThreadLocal要保存的副本变量为value,存到threadLocals。 然后在当前线程里面,如果要使用副本变量,就可以通过get方法在threadLocals里面查找。
实际的通过ThreadLocal创建的副本是存储在每个线程自己的threadLocals中的;
为何threadLocals的类型ThreadLocalMap的键值为ThreadLocal对象,因为每个线程中可有多个threadLocal变量,就像上面代码中的longLocal和stringLocal;
在进行get之前,必须先set,否则会报空指针异常;如果想在get之前不需要调用set就能正常访问的话,必须重写initialValue()方法。 因为在上面的代码分析过程中,我们发现如果没有先set的话,即在map中查找不到对应的存储,则会通过调用setInitialValue方法返回i,而在setInitialValue方法中,有一个语句是T value = initialValue(), 而默认情况下,initialValue方法返回的是null。
9.handler.post和handler.sendMessage本质上是没有区别的,都是发送一个消息到消息队列中,而且消息队列和handler都是依赖于同一个线程的。
send方案发送消息(需要回调才能接收消息)
1、sendMessage(Message) 立即发送Message到消息队列
2、sendMessageAtFrontOfQueue(Message) 立即发送Message到队列,而且是放在队列的最前面
3、sendMessageAtTime(Message,long) 设置时间,发送Message到队列
4、sendMessageDelayed(Message,long) 延时若干毫秒后,发送Message到队列
post方案 立即发送Message到消息队列
1、post(Runnable) 立即发送Message到消息队列
2、postAtFrontOfQueue(Runnable) 立即发送Message到队列,而且是放在队列的最前面
3、postAtTime(Runnable,long) 设置时间,发送Message到队列
4、postDelayed(Runnable,long) 在延时若干毫秒后,发送Message到队列
10.handler机制中包含4个关键类(下面对源码的解析也是从这4个类入手),Message(消息),MessageQueue(消息队列),Looper(轮询器),Handler(消息发送和接收并处理),简单一句话概括就是:handler负责发送message,将其加入到MessageQueue中,Looper不间断的从MessageQueue中取出消息,并发送给对应的handler实例去处理.
11.主线程与子线程
主线程((Ui线程,Main.thread):
定义:当应用程序第一次启动时,会同时开启1条主线程。
作用:处理与UI相关的事件(如更新操作等)。
子线程(工作线程):
定义:人为手动开启的线程。
作用:执行耗时操作(如网络请求、数据加载等)