Android Handler消息机制原理
①是什么?
Handler是Android SDK中处理异步类消息的核心类,其作用是让子线程通过与UI通信来更新UI界面
总结起来也可以这样说:
1.当应用程序启动时,会初始化一个UI线程
2.UI线程中创建了Looper,所以是一个循环工作线程
3.创建Looper时,Looper会创建一个MessageQueue
4.UI中的Looper会不断从MessageQueue中取出消息
②什么是Looper?什么是MessageQueue?
1)Looper: 一个线程可以产生一个Looper对象,由它来管理此线程里的MessageQueue(消息队列)。
2)Handler: 你可以构造Handler对象来与Looper沟通,以便push新消息到MessageQueue里;或者接收Looper从Message Queue取出)所送来的消息。
3) Message Queue(消息队列):用来存放线程放入的消息。
4)线程:UIthread 通常就是main thread,而Android启动程序时会替它建立一个MessageQueue。
③做什么?
(1).在新启动的线程中发送消息
(2).在主线程中获取,处理消息。
解释:(1) 当应用程序启动时,Android首先会开启一个主线程 (也就是UI线程) , 主线程为管理界面中的UI控件, 进行事件分发, 比如说, 你要是点击一个 Button ,Android会分发事件到Button上,来响应你的操作。 主线程(UI线程)就是android程序从启动运行到最后的程序。
(2) 如果此时需要一个耗时的操作,例如: 联网读取数据,或者读取本地较大的一个文件的时候,你不能把这些操作放在主线程中,如果你放在主线程中的话,界面会出现假死现象, 如果5秒钟还没有完成的话,会收到Android系统的一个错误提示 "强制关闭"。
(3)这个时候我们需要把这些耗时的操作,放在一个子线程中,因为子线程涉及到UI更新,Android主线程是线程不安全的, 也就是说,更新UI只能在主线程中更新,子线程中操作是危险的。
(4)这个时候,Handler就出现了。,来解决这个复杂的问题 ,由于Handler运行在主线程中(UI线程中), 它与子线程可以通过Message对象来传递数据, 这个时候,Handler就承担着接受子线程传过来的(子线程用sendMessage()方法传弟)Message对象(里面包含数据) , 把这些消息放入主线程队列中,配合主线程进行更新UI。
④怎么用?
handler可以分发Message对象和Runnable对象到主线程中,每个Handler实例,都会绑定到创建他的线程中(一般是位于主程),它有两个作用:
(1)合理调度安排消息和runnable对象,使它们在将来的某个点被执行.
(2)安排一个动作在不同的线程中执行
Handler中开启线程和分发消息的一些方法:
post(Runnable)直接开启Runnable线程
postAtTime(Runnable,long)在指定的时间long,开始启动线程
postDelayed(Runnable long)在延迟long时间后,启动Runnable线程
sendEmptyMessage(int) 发送指定的消息,通过参数int来区分不同的消息
sendMessage(Message)发送消息到UI线程中
sendMessageAtTime(Message,long) 这个long代表的是系统时间,不推荐用
sendMessageDelayed(Message,long) 此方法long代表调用后几秒后执行。
sendMessage类方法, 允许你安排一个带数据的Message对象到队列中,等待更新.
handler基本使用:1)在主线程中,使用handler很简单,new一个Handler对象实现其handleMessage方法,在 handleMessage 中提供收到消息后相应的处理方法即可。(接收消息,并且更新UI)
2)在新启动的线程中发送消息
⑤handler机制的原理
1.Handler创建消息
每一个消息都需要被指定的Handler处理,通过Handler创建消息便可以完成此功能。Android消息机制中引入了消息池。Handler创建消息时首先查询消息池中是否有消息存在,如果有直接从消息池中取得,如果没有则重新初始化一个消息实例。使用消息池的好处是:消息不被使用时,并不作为垃圾回收,而是放入消息池,可供下次Handler创建消息时使用。消息池提高了消息对象的复用,减少系统垃圾回收的次数。消息的创建流程如图所示。
2.Handler发送消息
UI主线程初始化第一个Handler时会通过ThreadLocal创建一个Looper,该Looper与UI主线程一一对应。使用ThreadLocal的目的是保证每一个线程只创建唯一一个Looper。之后其他Handler初始化的时候直接获取第一个Handler创建的Looper。Looper初始化的时候会创建一个消息队列MessageQueue。至此,主线程、消息循环、消息队列之间的关系是1:1:1。
Handler、Looper、MessageQueue的初始化流程如图所示:
Hander持有对UI主线程消息队列MessageQueue和消息循环Looper的引用,子线程可以通过Handler将消息发送到UI线程的消息队列MessageQueue中。
3.Handler处理消息
UI主线程通过Looper循环查询消息队列UI_MQ,当发现有消息存在时会将消息从消息队列中取出。首先分析消息,通过消息的参数判断该消息对应的Handler,然后将消息分发到指定的Handler进行处理。