带着问题学习

  1. Handler 的作用是什么?
  1. 为什么在主线程中可以直接使用 Handler,而不需要创建 Looper?
  1. 为什么在子线程中不能直接使用 Handler,而要先用 Looper.prepare()?
  1. Handler 的 post() 和 send 有什么区别?
  1. Handler 的 postDelay() 是准确的延时吗?
  1. Handler 中的 messageQueue 是什么样的结构?
  1. Handler 中的死循环为什么不会一直占用 CPU 资源?
  1. 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

关系图

notion image
notion image

总结

从上面的分析,可以看出,一个完整的消息处理机制,包含了封装消息的 Message,发送消息的 Handler,缓存消息的 MessageQueue,以及获取并处理消息的 Looper ,这也就解释了,为什么在子线程中,一定要先调用 prepare() 来可以,因为子线程原本是没有 Looper 与之绑定的,需要先创建一个,才能使得整个消息处理机制完整
HandlerThread 源码解析Retrofit 缓存机制