带着问题学习
Handler的作用是什么?
- 为什么在主线程中可以直接使用
Handler,而不需要创建Looper?
- 为什么在子线程中不能直接使用
Handler,而要先用Looper.prepare()?
Handler的post()和send有什么区别?
Handler的postDelay()是准确的延时吗?
Handler中的messageQueue是什么样的结构?
Handler中的死循环为什么不会一直占用 CPU 资源?
Handler、Looper、MessageQueue之间是怎么工作的?
简介
Android开发的世界里,流传着一个说法:只能在UI线程中更新UI
- 但是我们耗时操作都是在子线程中进行的,而且往往执行完耗时操作,要把耗时操作的结果更新到界面中显示出来,这就避免不了要进行更新
UI的操作,可是,我们是在子线程中获取到的结果,要怎么才能无痛地将结果显示到界面中呢?
- 这时候,就需要用到一种 线程间的消息机制:Handler,也就是说,
Handler主要是进行线程间通信的,也就是把 子线程 的消息,发送给 主线程,从而达到 更新UI的目的
作用
看看官方的说法
to schedule messages and runnables to be executed at some point in the future to enqueue an action to be performed on a different thread than your own.
- 执行定时任务
- 把任务交给其他线程执行
组成
先来看看
Handler 工作时,其必要的组成是什么。后面一一进行解析- Handler
- MessageQueue
- Looper
大概原理
Handler 用于将消息或者 Runnable 对象投递到消息队列(MessageQueue)中,然后由 Looper 从消息队列中取出消息并进行处理使用步骤
具体的使用过程,已经写过相关的文章了,不赘述,下面是相关的步骤
- 创建 Handler 对象
- 在子线程中调用 handler
- 启动子线程
Handler 源码解析
先给结论,
Handler 中不论是通过 post 还是 send 发送消息,最后都是通过 sendMessageDelayed() 方法发送消息到消息队列中Handler 的定义
可以看到
Handler 里面有三种发送消息的方法,根据这些方法,还有相关的重载,下面来一个个看具体实现前置方法
- getPostMessage
post
post
postDelayed
可以看到,不管是
post 还是 postDelayed 都是调用的 sendMessageDelayed() 方法,所以下面来看看其具体实现从上面的调用关系可以看出,对于需要
post 的消息,最终都是调用的 enqueueMessage 把消息压入消息队列,等待执行send
发送消息还有一种方法,那就是
send 类方法sendMessage
sendEmptyMessage
sendEmptyMessageDelayed
sendMessageDelayed具体实现已经在上面跟踪post方法的调用流程中看过了
Message
从上面发送消息的过程分析中,可以看到,我们虽然一开始发送的有
runnable 和 message 两种对象,但是最后调用 sendMessageDelayed() 发送消息时,都是统一成了 Message 对象,也就是说 message 才是最终的消息对象,接下来就来看看 Message 对象的源码定义
创建 Message 的方法
- 构造方法
从官方自己的注释可以看出,官方推荐使用
Message.obtain() 来获取 Message 对象,因为通过构造函数创建的 Message 对象,是无法复用的Message.obtain()因为Message.obtain的重载方法都差不多,所以只看一个就够了
回收 Message 的方法
从上面的源码中可以看出,当我们需要 获取 or 创建 一个
Message 对象时,最好是通过 Message.obtain() 的方式,因为其内部自动实现了一个 pool 来实现复用,在多次调用中,可以避免多次 new Message() 的开销MessageQueue
- 上面已经解析了
Handler和Message,接下来应该看看,Handler把Message对象,具体send到的MessageQueue对象是怎么样的了
- 来看看官方对这个类的注释
Low-level class holding the list of messages to be dispatched by a Looper. Messages are not added directly to a MessageQueue, but rather through Handler objects associated with the Looper.
- 即不能直接往这个类中添加
Message对象,而应该通过handler来往MessageQueue中添加Message对象MessageQueue的方法很多,只看看重要的方法
enqueueMessage
从上面的代码中,
enqueueMessage 的功能可以概括为:根据 message 的启动时间,在 messageQueue 中找到合适的位置,并插入next
Looper
有了封装消息的
Message,发送消息的 Handler,缓存消息的 MessageQueue,接下来看看获取并处理消息的 Looper创建 looper——prepare
获取消息——loop
销毁Looper——quit
关系图

总结
从上面的分析,可以看出,一个完整的消息处理机制,包含了封装消息的
Message,发送消息的 Handler,缓存消息的 MessageQueue,以及获取并处理消息的 Looper ,这也就解释了,为什么在子线程中,一定要先调用 prepare() 来可以,因为子线程原本是没有 Looper 与之绑定的,需要先创建一个,才能使得整个消息处理机制完整- Author:CoderWdd
- URL:https://www.wuinsights.top//article/5ef3fbc2d7e7
- Copyright:All articles in this blog, except for special statements, adopt BY-NC-SA agreement. Please indicate the source!
Relate Posts