Android之Handler、Message、MessageQueue、Looper详解
Handler
Handler的原理
Handler的原理:
Android中主线程是不能进行耗时操作的,子线程是不能进行更新UI的。所以就有了Handler,它的作用就是实现线程之间的通信。
Handler整个流程中,主要有四个对象,handler,Message,MessageQueue,Looper。当应用创建的时候,就会在主线程中创建handler对象,我们通过要传送的消息保存到Message中,handler通过调用sendMessage方法将Message发送到MessageQueue中,Looper对象就会不断的调用loop()方法 不断的从MessageQueue中取出Message交给handler进行处理。从而实现线程之间的通信。
线程间通信的实现步骤
线程间通信的实现步骤:
- 在主线程中定义Handler的子类
- 重写Handler类的handleMessage()方法
- 用该子类定义全局的Handler对象,以便子线程使用
- 子线程获得handler对象用该对象的sendMessage()方法发送消息
Handler的应用场景
Handler在Android开发中有多种应用场景,以下是几种常见的使用情况:
- 子线程通知主线程更新UI:
Android规定只能在主线程(也称UI线程)中对界面元素进行操作。当需要在后台线程中执行耗时任务(如网络请求、数据库查询、大量计算等)后更新UI时,可以使用Handler来发送消息或Runnable到主线程,确保在主线程中正确、安全地更新界面。- 延迟任务或定时任务:
Handler提供了postDelayed(Runnable, long)和sendMessageDelayed(Message, long)等方法,可以安排一个任务在未来某个时间点执行。这种机制适用于实现倒计时、动画帧刷新、定期状态检查、登录超时提醒等功能。- 处理下载或加载进度:
在进行文件下载、大图加载等涉及进度变化的操作时,后台线程可以通过Handler不断发送进度更新消息到主线程,以便在界面上实时显示进度条或其他进度反馈。- 事件总线(Event Bus)机制:
在复杂的应用中,Handler可以作为轻量级的事件传递机制,不同组件通过发送消息到共享的Handler来实现跨组件通信。尽管有专门的事件总线库(如 Otto、EventBus)更为高效和便捷,但Handler也能满足简单的事件发布与订阅需求。- 协同多个线程间的任务序列:
当需要在多个线程间按特定顺序执行一系列任务时,Handler可以用来协调这些任务的调度。例如,一个线程完成部分工作后,通过Handler发送消息触发下一个线程开始执行,以此保证任务按照预期流程进行。- 响应系统事件:
Handler可以注册接收系统级别的消息,如系统时间变更、设备方向改变等。通过重写handleMessage()方法并检查消息类型,可以对这些事件做出相应处理。总的来说,当遇到以下需求时,可以考虑使用Handler:
- 跨线程通信,特别是从子线程向主线程发送消息或指令。
- 需要延迟执行的任务,无论是单次的延迟执行还是周期性的定时任务。
- 涉及UI更新的操作,特别是在后台任务完成后需要更新界面的状态。
- 实现简单的事件驱动编程模型,在不同组件或模块之间传递事件消息。
- 响应特定的系统事件,在收到特定系统消息时执行特定逻辑。
- 只要涉及到线程间消息传递、任务调度或UI更新控制,尤其是需要遵循Android主线程更新规则的情况,Handler都是一个有效的工具。
Handler在多线程中的应用
- 发送消息,在不同的线程间发送消息,使用的方法为sendXXX();。
android.os.Handler对象通过下面的方法发送消息的:
- sendEmptyMessage(int):发送一个空的消息;
- sendMessage(Message):发送消息,消息中可以携带参数;
- sendMessageAtTime(Message, long):未来某一时间点发送消息;
- sendMessageDelayed(Message, long):延时Nms发送消息。
- 计划任务,在未来执行某任务,使用的方法为postXXX();。
android.os.Handler对象通过下面的方法执行计划任务:
- post(Runnable):提交计划任务马上执行;
- postAtTime(Runnable, long):提交计划任务在未来的时间点执行;
- postDelayed(Runnable, long):提交计划任务延时Nms执行。
如何在子线程中创建Handler
如何在子线程中创建Handler?
- 创建一个 HandlerThread,即创建一个包含 Looper 的线程HandlerThread 的构造函数有两个
- 通过 HandlerThread 的 getLooper 方法可以获取 Looper
- 通过 Looper 我们就可以创建子线程的 handler 了
- 通过该 handler 发送消息,就会在子线程执行;
如果要 handlerThread 停止: handlerThread.quit();
Hander中removeMessages方法
Hander中removeMessages方法
- 这个方法使用的前提是之前调用过sendEmptyMessageDelayed(0, time),意思是延迟time执行handler中msg.what=0的方法;
- 在延迟时间未到的前提下,执行removeMessages(0),则上面的handler中msg.what=0的方法取消执行;
- 在延迟时间已到,handler中msg.what=0的方法已执行,再执行removeMessages(0),不起作用。
- 该方法会将handler对应message队列里的消息清空,通过msg.what来找到对应的message。
- 当队列中没有message则handler会不工作,但并不是handler会停止,当队列中有新的message进来后,会继续处理执行。