Android消息机制
这篇文章主要目的是简单总结消息机制的工作原理以及解决一些疑惑点
概述
Android的消息机制主要是指 Handler 的运行机制,这个机制不仅包含发送消息的 Handler ,还包含消息存储单元 MessageQueue 和 不停从 MessageQueue 取出消息的 Looper 。
其实 Handler 的主要作用的将一个任务切换到指定的线程中去执行,比如在子线程内将文本内容传递到 UI 主线程更新 UI,不过这个文本内容被我们抽象化成了 消息。
工作原理图
从右边的方框开始讲起。
- 平时开发中 Looper 和 MessageQueue 已经由系统在主线程中创建出来了,我们的工作是在 UI主线程手动创建一个 Handler 实例。通过 Handler 实例 的 sendMessage 方法将一个 Message 发送出去,而这个消息的“发送”其实是被添加到 MessageQueue 中,再由做死循环的 Looper 从 MessageQueue 取出这个消息,交给 Handler 的 dispatchMessage 函数处理,在此函数中会判断是否调用我们重写的 handlerMessage 函数。
- 注意其中 子线程中的 Handler 和主线程中是同一个 Handler ,所以就能做到上面提到的,将任务切换到指定线程中的功能。
基本原理就这样,比较简单,接下来解决经典问题。
Looper 在主线程中做死循环取消息,平时我们没有使用到 Handler 发消息时主线程也没有卡死?
- 实际上 Android 中 Activity 的生命周期和屏幕的点击事件等都算是消息,这些消息都由 Looper 取出来交给 Handler 来处理。
- 那假设上述事件都没有时,也就是没有消息产生后,怎么还是没有卡死?
- 这里就涉及到 Linux pipe/epoll 机制,简单说就是在主线程的 MessageQueue 没有消息时,便阻塞在loop 的 queue.next() 中的 nativePollOnce() 方法里,此时主线程会释放CPU资源进入休眠状态,直到下个消息到达或者有事务发生,通过往 pipe 管道写端写入数据来唤醒主线程工作。
- 这里采用的 epoll 机制,是一种IO多路复用机制,可以同时监控多个描述符,当某个描述符就绪(读或写就绪),则立刻通知相应程序进行读或写操作,否则处于阻塞状态但不会卡主。 所以说,主线程大多数时候都是处于休眠状态,并不会卡死。
参考资料
- Android开发艺术探索》
- Android中为什么主线程不会因为Looper.loop()里的死循环卡死? - 知乎