1. Android 消息机制概述
Android 的消息机制主要是指 Handler 的运行机制以及 Handler 所附带的 MessageQueue 和 Looper 的工作机制,这三者是一个整体
Handler 的主要作用是将一个任务切换到某个指定的线程中去执行
Android 为什么需要提供在某个具体的线程中执行任务这种功能?
因为 Android 规定访问 UI 只能在主线程(UI 线程,即 ActivityThread)中进行,如果在子线程中访问 UI,那么程序会抛出异常
ViemRootImpl 对 UI 操作做了验证,这个验证工作是由 ViewRootImpl 的
checkThread()
方法来完成的:1
2
3
4
5void checkThread() {
if (mThread != Thread.currentThread()) {
throw new CalledFromWrongThreadException("Only the original thread that created a view hierarchy can touch its views.");
}
}
Android 建议不要在主线程中进行耗时操作,否则可能导致程序无响应即 ANR
系统之所以提供 Handler,主要原因就是为了解决在子线程中无法访问 UI 的矛盾
2. 为什么不允许在子线程中访问 UI
- 因为 Android 的 UI 控件不是线程安全的,如果在多线程中并发访问可能会导致 UI 控件处于不可预期的状态
3. 为什么系统不对 UI 控件的访问加上锁机制
缺点有两个:
- 首先,加上锁机制会让 UI 访问的逻辑变得复杂,而应用的主要逻辑都体现在 UI 交互上
- 其次,锁机制会降低 UI 访问的效率,因为锁机制会阻塞某些线程的执行
因此,最简单且高效的方法就是采用单线程模型来处理 UI 操作
4. Handler 工作原理概述
Handler 创建时会采用当前线程的 Looper 来构建内部的消息循环系统
- 如果当前线程没有 Looper 就会报错:
java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
- 解决上述报错的方法:为当前线程创建 Looper 即可,或者在一个有 Looper 的线程中创建 Handler 也行
- 如果当前线程没有 Looper 就会报错:
线程是默认没有 Looper 的,如果需要使用 Handler 就必须为线程创建 Looper。主线程,即 ActivityThread 被创建时就会初始化 Looper,这也是在主线程中默认可以使用 Handler 的原因
Handler 创建完毕后,此时内部的 Looper 以及 MessageQueue 就可以和 Handler 一起协同工作了。然后通过 Handler 的
post()
方法将一个 Runnable 投递到 Handler 内部的 Looper 中去处理,也可以通过 Handler 的send()
方法发送一个消息,这个消息同样会在 Looper 中去处理,其实post()
方法最终也是通过send()
方法来完成的send()
方法的工作过程:- 当 Handler 的
send()
方法被调用时,它会调用 MessageQueue 的enqueueMessage()
方法将这个消息放入消息队列中进行入队操作 - 然后 Looper 发现有新消息到来时,就会处理这个消息,最终消息中的 Runnable 或者 Handler 的
handleMessage()
方法就会被调用 - 注意 Looper 是运行在创建 Handler 所在的线程中的,这样一来 Handler 中的业务逻辑就被切换到创建 Handler 所在的线程中去执行了
- 当 Handler 的