Android Handler深入学习(源码分析)

目录:
目录

1. 前言

在上一篇关于 Android Handler使用方法 的文章中学会了 Handler 的使用方法,然而又是知其然不知其所以然的状态,这次较深入的学习一下 Handler 的源码。

在分析源码之前,先来了解一下Message、MessageQueue、Looper这几个对象。

1.1 Message 消息

定义:是线程间通讯的数据单元,包含着描述信息及任意数据对象,发送到 Handler。

在实际使用中,我们在工作线程中通过 Handler.sendMessage(Message),将携带数据的 Message 信息发送给 Handler,然后再由 Handler 处理,根据不同的信息,通知主线程作出相对应的 UI 工作。

官方文档说明:

/**
 * 定义包含着描述信息及任意数据对象的可发送到 Handler 的信息。额外包含可以不被分配的两个 int 字段及一个 Object 字段。
 * 获取 Message 对象最好的方法是调用 Message.obtain() 或 调用 Handler.obtainMessage() 方法来获取,调用该方法将从可回收的对象池中获取对象。
 */
public final class Message implements Parcelable {
   
    /**
     * 用户定义的消息代码,以便接收者能够识别此消息。每个 Handler 都有自己的消息代码命名空间,因此不必担心你的 Handler 与其他 Handler 起冲突。
     */
    public int what;

    /**
     * 如果只需要存储几个整数值,以 arg1 和 arg2 为变量去使用 setData(Bundle) 是较低成本的替代选择方法。
     */
    public int arg1;
    public int arg2;

    /**
     * 发送给接收者的任意对象,当使用 Messager 跨进程发送消息时,如果包含着可序列化的框架类时,Message必须是非空的。使用setData()来传输数据。
     * 注意,Android 2.2发行版之前不支持此处的Parcelable对象。
     */
    public Object obj;
    ···略···

1.2 MessageQueue 消息队列

定义:用来存储 Message 的数据队列。

官方文档说明:

/**
 * 包含着一系列由 Looper 分发的 Message 的一个低级类。
 * Message 不是直接添加到 MessageQueue 中的,而是通过与 Looper 关联的 Handler 对象来添加的。
 * 你可以使用“loop.myQueue()”方法来获取当前线程的 MessageQueue 对象。
 */
public final class MessageQueue {
   
    private static final String TAG = "MessageQueue";
    ···略···
}

1.3 Looper 消息循环器

定义:用于为线程执行消息循环的一个类。是 MessageQueue 与 Handler 之间的通讯媒介。

官方文档说明:

/**
  * 用于为线程执行消息循环的一个类。
  * 线程默认情况下没有与之关联的消息循环;要创建一个,在将要运行循环的线程中调用 Looper.prepare(),然后调用 Looper.loop() 让它处理消息,直到循环停止。
  * 与消息循环的大多数交互都是通过 Handler 类进行的。
  * 这是一个典型的 Looper 线程实现的例子,使用 Looper.prepare() 和 Looper.loop() 方法创建一个 Handler 对象与 Looper 进行通信。
  * <pre>
  *  class LooperThread extends Thread {
  *      public Handler mHandler;
  *
  *      public void run() {
  *          Looper.prepare();
  *
  *          mHandler = new Handler() {
  *              public void handleMessage(Message msg) {
  *                  // 在这里处理传入的消息
  *              }
  *          };
  *
  *          Looper.loop();
  *      }
  *  }</pre>
  */
public final class Looper {
   
     /*
     * API 实现注意事项:
     *
     * 该类包含设置和管理基于 MessageQueue 的事件循环所需的代码。
     * 影响队列状态的api应该在 MessageQueue 或 Handler 上定义,而不是在 Looper 本身上定义。
     * 例如,在队列上定义空闲处理程序和同步屏障,而在 Looper 上定义线程准备、循环和退出。
     */

    private static final String TAG = "Looper";
    ···略···
}

1.4 Message、MessageQueue、Looper之间的关系

一句话概括:
存储在 MessageQueue 中的 MessageLooper 循环分发到指定的 Handler 中进行处理。

2. Handler 通信机制原理

关于Handler的通信机制工作原理,请看 Carson_Ho大佬的 Android Handler:图文解析 Handler通信机制 的工作原理 写的超棒,图文解析,一目了然。引用其中一Handler通信流程示意图,如下:
在这里插入图片描述

Thread、Handler、Looper三者之间的数量对应关系;

  • 一个 Thread 可以有多个 Handler。
  • 但一个 Thread 只能由一个 Looper。
  • 一个 Handler 只能关联一个 Looper 对象。
  • 反之,一个 Looper 可以被多个 Handler 所关联。

3. 源码分析

根据上一篇博客中介绍的Android Handler 使用方法, 我们针对 Handler.sendMessage(msg) 方法展开分析,分为3步:

  1. 创建 Handler 对象
  2. 创建 Message 对象
  3. 分发 Message

3.1 创建 Handler 对象

创建一个 Handler 对象,也就是实例化一个 Handler 对象,在实际的使用中,我也发现有存在三种情况,分别是:

  1. 在主线程上新建一个 Handler 对象,提供应用程序的 主Looper 对象与之绑定关联。
  2. 创建一个继承于 Handler类的静态内部类,防止内存泄漏。
  3. 在子线程上创建 Handler 对象。

我将一一展开分析:

3.1.1 在主线程上新建一个 Handler 对象,提供应用程序的 主Looper 对象与之绑定关联

如下,我们在主线程中新建 Handler 对象,

//在主线程中新建 Handler 对象,并提供应用程序的 主Looper
mHandler = new Handler(Looper.getMainLooper()) {
   
    @Override
    public void handleMessage(Message msg) {
   
        super.handleMessage(msg);
        //消息处理

    }
};

通过上述代码,我们创建了一个 Handler 对象,并关联应用程序的 主Looper 对象。
这个时候我们看一下 Handler类 的构造函数,如下所示:

/**
 * Use the provided {@link Looper} instead of the default one.
 * 使用提供的 Looper对象, 而不是使用默认的Looper对象
 * @param Looper 不能为 null
 */
public Handler(@NonNull Looper looper) {
   
    this(looper, null, false);
}

可以发现,我们提供给 Handler 的 Looper 是通过 Looper.getMainLooper() 获取的。往下看:

/**
 * 返回应用程序的 主Looper, 它存在于应用程序的主线程中。
 */
public static Looper getMainLooper() {
   
    synchronized (Looper.class) {
   
    	//返回sMainLooper, 下一步看看sMainLooper是怎么创建 Looper 对象的。
        return sMainLooper; 
    }
}

如上所诉,getMainLooper() 返回 全局变量 sMainLooper 对象,所以我们需要看 sMainLooper 是什么时候被赋值的,如下所示,在 prepareMainLooper() 方法中,sMainLooper 被 myLooper 赋值:
/**
 * 将当前线程初始化为 Looper,并将其标记为应用程序的 主Looper
 * 应用程序的 主Looper 是由 Android环境 创建的,所以永远不需要自己调用这个函数
 */
public static void prepareMainLooper() {
   
    //调用 prepare() 方法,如果当前线程没有 Looper 对象,就为之新创建一个 Looper 对象。
    prepare(false);
    synchronized (Looper.class) {
   
        if (sMainLooper != null) {
   
            throw new IllegalStateException("The main Looper has already been prepared.");
        }
        //返回当前线程所关联的 Looper 对象。
        sMainLooper = myLooper();
    }
}

上一步 prepareMainLooper 中:调用了 prepare(false) 来创建 Looper 对象,具体如下:
private static void prepare(boolean quitAllowed) {
   
    //sThreadLocal.get() 返回 Looper
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值