Android消息机制原理

一. 概述:Handler、消息队列和Looper

  1. Handler的功能:将一个任务切换到某个指定的线程中去执行。
  2. UI线程:Handler常见于从工作线程切换到UI线程。因为Android UI使用的是单线程模式,不允许在其它子线程中访问UI。如果在多线程中并发访问UI,可能导致UI控件处于不可控的状态,它不是线程安全的。
  3. 工作流程:

    image

    1. Thread2中创建Handler对象,Handler内部维护一个Looper和消息队列。
    2. 在Thread1中对该Handler对象发送消息。
    3. Looper不断循环从消息队列中取出消息来处理
    4. 此时Handler的handleMessage是运行在Thread2中。哪个线程创建了Handler对象,那么最终处理消息时的工作就已经切换到该线程中。

二. 消息机制分析

  1. ThreadLocal机制:
    • 当一个变量以线程为作用域,而且每个线程都需要拥有独立的变量副本时,就适合使用ThreadLocal
    • 具体到Androd,对于Handler来说,Looper的作用域就是线程,而且每个线程都拥有独立的Looper。此时使用ThreadLocal就非常合适。
    • 其它的用途场景:每个线程都需要一个独立的监听器对象时。
    • 关于ThreadLocal,我单独再开一篇来阐述。
  2. 消息队列(MessageQueue)的工作原理:

    1. enqueueMessage方法: 插入一条消息进入队列。
    2. next方法:取出一条消息,并从队列移出。这是个无限循环的方法,如果队列中没有消息,就会一直阻塞。当有新消息到来时,next方法会返回这条消息,并将其从单链表中移出。
  3. Looper工作原理:

    1. 创建:

      new Thread(){
          public void run() {
              Looper.prepare();
              Handler handler = new Handler();
              Looper.loop();
          }
      }.start();
    2. 退出Looper:quitquitSafely方法。其中quitSafely并不立刻退出,而是等队列中已有的消息处理完毕后才会退出。
      • 退出Looper后,Handler的send会返回false,消息发送将会失败。
      • 在子线程中,如果手动创建了Looper,应当在所有事情完成后,调用quit方法来终止循环,否则这个子线程将一直处于等待状态。
      • 调用loop方法后,消息循环系统才会开始工作。
      • loop方法是一个死循环,只有当quit或quitSafely调用时,才会退出循环。
  4. Handler的工作原理
    • 发送消息:向消息队列中插入一条消息,MessageQueue的next方法就会返回这条消息给Looper,接着Looper就会处理这条消息,但最终,Looper会将这条消息交由Handler来处理,dispatchMessage方法会被调用,Handler进入处理消息的阶段。
    • 处理消息:
      1. 检查Message的callback(一个Runnable对象)是否为null,不为null就通过handleCallback来处理消息。
      2. 检查mCallback是否为null,不为null就调用handleMessage来处理消息。你可以通过Handler的构造方法传入一个Callback,这样就无需派生一个Handler的子类了。
      3. 最后调用Handler的handleMessage方法来处理消息。
    • 你也可以手动创建Looper来构造Handler。

三. 主线程的消息循环

  1. Android的主线程就是ActivityThread,入口方法为main,在main方法中系统会通过Looper.prepareMainLooper()来创建主线程的Looper和MessageQueue,并调用loop开启循环。

  2. ActivityThread.H: 主线程的Handler。

    • 它通过ApplicationThread和AMS远程通信。AMS在以IPC方式完成ActivityThread的请求后,会回调ApplicationThreadBinder方法,然后ApplicationThread会给H发送消息。
    • H收到消息后,会将ApplicationThread中的逻辑切换到ActivityThread中执行,即切换到主线程中去执行。

猜你喜欢

转载自blog.csdn.net/cangely/article/details/80270542