首页 > 系统 > Android > 正文

# 读 Android 开发艺术探索 &11

2019-11-09 17:53:42
字体:
来源:转载
供稿:网友

关键词:消息机制 / Handler

本次笔记梳理了和 Android 的消息机制的知识点。Handler 是 Android 消息机制的上层接口,通过它可以轻松将一个任务切换到 Handler 所在的线程中去执行。Android 的消息机制主要是指 Handler 的运行机制,Handler 的运行需要底层的 MessageQueue 和 Looper 的支撑。 有时候需要在子线程中进行耗时的 I/O 操作,可能是读取文件或者访问网络等,当耗时操作完成之后可能要在 UI 上做一些改变,由于 Android 开发规范的限制,我们并不能在子线程中访问 UI 控件,否则就会触发程序异常,这个时候通过 Handler 就可以将更新 UI 的操作切换到主线程中执行。(所以 Handler 常被开发者用来更新 UI)

1. Handler #

系统之所以提供 Handler,主要原因是为了解决在子线程中无法访问 UI 的矛盾;Handler 的主要作用就是将一个任务切换到某个指定的线程中去执行;为什么不能在子线程中访问 UI 呢?因为 Android 的 UI 控件不是线程安全的;Handler 的工作主要包含消息的发送和接收过程,消息的发送可以通过 post 的一系列方法以及 send 的一系列方法来实现,post 的一系列方法最终是通过 send 的一系列方法来实现的;Handler 发送消息的过程仅仅是向消息队列插入了一条消息,MessageQueue 的 next 方法就会返回这条消息给 Looper,Looper 收到消息后就开始处理了,最终消息由 Looper 交由 Handler 处理,即 Handler 的 dispatchMessage 方法会被调用,这时 Handler 就进入了处理消息的阶段;

2. Looper 和 ThreadLocal #

ThreadLocal 是 Looper 中的一个比较特殊的概念,它不是线程,作用是可以在每个线程中存储数据;Handler 内部如何获取当前线程的 Looper? 便是使用 ThreadLocal,ThreadLocal 可以在不同的线程中互不干扰地存储并提供数据,通过 ThreadLocal 可以轻松获取每个线程的 Looper;ThreadLocal 是一个线程内部的数据存储类,通过它在指定的线程中存储数据,数据存储之后,只有在指定线程中可以获取到存储的数据,对于其他线程来说则无法获取到数据;一般来说,当某些数据是以线程为作用域并且不同线程具有不同的数据副本的时候,可以考虑采用 ThreadLocal;ThreadLocal 的另一个使用场景是 复杂逻辑下的对象传递,比如监听器的传递;采用 ThreadLocal 可以让监听器作为线程内的全局对象而存在,在线程内部只要通过 get 方法就能获取到监听器;采用 ThreadLocal,每个监听器对象都在自己的线程内部存储;不同线程中访问的是同一个 ThreadLocal 对象,但是它们通过 ThreadLocal 获取到的值确实不一样的,这是 ThreadLocal 的奇妙之处;

ThreadLocal 是一个泛型类 public class ThreadLocal<T>;

Looper 扮演着消息循环的角色,不停的从 MessageQueue 中查看是否有新消息,如果有新消息就会立刻处理,否则会一直阻塞在那里;

Handler 的工作需要 Looper,没有 Looper 的线程就会报错;通过 Looper.PRepare() 即可为当前的线程创建一个 Looper,接着通过 Looper.loop() 来开启消息循环;quit 会直接退出 Looper,而 quitSafely 只是设定一个退出标记;Looper 必须要有退出,否则 loop 方法就会无限循环下去

3. MessageQueue #

消息队列主要包含两个操作:插入 和 读取;分别对应着方法:enqueueMessage 和 next读取操作本身会伴随着删除操作;MessageQueue 的内部实现并不是用的队列,而是通过一个单链表的数据结构来维护消息列表,单链表在插入和删除上比较有优势;next 是一个无限循环的方法,如果消息队列中没有消息,next 方法会一直阻塞在那里,当有新消息到来时,next 的方法会返回这条消息并将其从单链表中移除;

End.

Note by HF. Learn from 《Android 开发艺术探索》



发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表