0%

Android 的消息机制(一):Android 的消息机制概述

1. Android 消息机制概述

  • Android 的消息机制主要是指 Handler 的运行机制以及 Handler 所附带的 MessageQueueLooper 的工作机制,这三者是一个整体

  • Handler 的主要作用是将一个任务切换到某个指定的线程中去执行

  • Android 为什么需要提供在某个具体的线程中执行任务这种功能?

    • 因为 Android 规定访问 UI 只能在主线程(UI 线程,即 ActivityThread)中进行,如果在子线程中访问 UI,那么程序会抛出异常

    • ViemRootImpl 对 UI 操作做了验证,这个验证工作是由 ViewRootImpl 的 checkThread() 方法来完成的:

      1
      2
      3
      4
      5
      void 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 的,如果需要使用 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 所在的线程中去执行了
-------------------- 本文结束感谢您的阅读 --------------------