前言
网上关于Handler机制运行原理的文章已经很多,但毕竟不是自己的,也不一定适合自己的阅读习惯!
一、概述
Android 的消息机制主要是指 Handler 的运行机制, Handler 的运行需要底层的 MessageQueue 和 Looper 支撑,这三者实际上是一个整体 ( 配套使用 ) ,只不过我们在开发过程中比较多的接触到 Handler 而已。
说到 Handler ,很多人都知道是为了更新 UI ,这不错,但这只是 Handler 的一个应用场景而已。
Handler 出现的原因,我想是因为不能在主线程中做耗时操作,一旦耗时操作超过 5s 就会出现 ANR 异常,下面代码是 Handler 的最常用用法:
|
|
注意:
线程中默认是没有 Looper的,如果想要使用 Handler 就必须为线程创建 Looper ,否则会报错,Looper 是运行在 Handler 所在的线程中的。
主线程比较特殊,它在创建的时候就会初始化 Looper,会调用 Looper.prepaerMainLooper() 来创建主线程的 looper 以及 MessageQueue ,也就是说,在主线程中默认可以使用 Handler 。
大致的原理:
Handler 通过 send 或 post 的 一系列方法发送 message 到 MessageQueue 。
MessageQueue 翻译过来叫做消息队列,内部存储 Handler 发送过来的一系列消息,仅仅能存储消息,数据存储结构为单链表。
Looper 会以无限循环的方式从 MessageQueue 中查找是否有新消息,如果有就处理消息,否则就一直等待着。
二、详细分析
主要介绍下 ThreadLocal 、 Handler 、 MessageQueue 、Looper
1. ThreadLocal
ThreadLocal 是一个线程内部的数据存储类,通过它可以在指定的线程中存储数据,数据存储以后,只能在指定线程中才可以获取到存储的数据。
介绍 ThreadLocal 是因为不同线程的 Handler 获取对应 Looper 采用的就是这个原理。
举个例子:
|
|
代码中,在主线程中设置 mBooleanThreadLocal 为 true ,在 Thread—1 中设置 mBooleanThreadLocal 为 false ,在 Thread—2 中没有设置, mBooleanThreadLocal 通过 set() 和 get() 方法进行数据的设置和取出操作。
打印出来的结果为:
|
|
从上边的日志可以看出,在不同线程中访问同一个 ThreadLocal 对象,
获得的值却是不一样的,原因就是:ThreadLocal 内部会从各自的线程中取出一个数组,
然后再从数组中根据当前 ThreadLocal 的索引去查找对应的 value 值,而不同线程中的数组是不同的,
所以取出的值也不一样。
2. MessageQueue
翻译过来为消息队列,其主要包含两个操作:插入和读取,分别对应 MessageQueue 的两个方法 enqueueMessage() 和 next() ,另外,读取过的消息会删除掉!
3. Looper
Looper 会不停的从 MessageQueue 中查看是否有新消息,有就立刻处理,否则就一直阻塞,在 Looper 的构造方法中会创建一个 MessageQueue 对象,再次印证了那四个字—配套使用。
|
|
除了主线程之外,在其他线程中如何创建 Looper 对象,如下所示:
|
|
获取主线程 Looper, 通过方法:Looper.getMainLooper();
Looper 退出,有两个方法,Looper 的 quit() 和 quitSafely() ,其内部还是让 MessageQueue 的 next 方法返回 null , next 方法返回 null 是唯一的退出方式 ,建议不需要的时候终止 Looper。
quit() 是直接退出 Looper 。
quitSafely() 是把已有的消息处理完之后才安全退出。
4. Handler
handler 的工作主要是发送和接收消息的过程
发送消息是通过一系列的 send 和 post 方法来发送的,而 post 的一系列方法最终还是通过 send 实现的,发送一条消息的过程如下:
|
|
从上边可以发现,Handler 发送消息,实际上只是在消息队列中插入了一条消息。
MessageQueue 的 next 方法会将这条消息返回给 Looper ,最终这条消息由 Looper 交给 Handler 的 dispatchMessage 方法处理,如下所示:
|
|
最后,调用 Handler 的 handlerMessage 方法来处理消息。