源码分析 Handler 机制(五) —— 总结

本文基于 SDK-33

简短概括 Handler 机制

前面四篇文章单独分析了 Handler 机制中四个最主要的部分,那么纵观全局来查看一下整个 Handler 机制的工作过程:

  1. 在线程中创建 Handler。

    如果是在子线程中创建,还需手动创建 Looper 对象,并调用 Looper.loop 开启轮询。

    如果是在主线程创建,则无需手动创建 Looper,因为系统已经自从创建并开启了 loop

  2. 开启 loop 之后,此时 Looper 中的 MessageQueue 还没有消息,此时 native 层会一直等待,Looper 的 loop 循环也会一直处于等待 MessageQueue 的 next 方法返回 Message 的状态中。

  3. 通过 Handler 对象发送 Message,调用 MessageQueue 的 enqueueMessage 方法将消息压入自身维护的队列中,并在确定是否唤醒 native 层。

  4. 如果插入的 Message 唤醒了 MessageQueue,则 Looper 调用的 next 方法可以获取到 Message,然后就可以调用 Message 绑定的 target(Handler)对象的 dispatchMessage 方法了。

  5. dispatchMessage 方法会将 Message 交由 handleCallback 或者 handleMessage 处理。

  6. handleMessage 执行之后,Looper 会将 Message 回收。

整个流程大致上就是上面这样的。

一些问题

Handler、Looper、MessageQueue、Thread 的对应关系

MessageQueue 和 Thread 都是 Looper 对象的变量,也就是说,Looper 和 MessageQueue 和 Thread 是绑定的,是一一对应的关系。

在 Looper 中维护了一个 ThreadLocal 对象,以保证一个线程的整个生命周期只会和一个 Looper 进行绑定。

在任何线程内都可以创建 Handler,都可以和 mainLooper 进行关联,所以 Handler 和 Looper 是一对多的关系。

handleMessage 运行在主线程中的吗?

不一定。

handleMessage 运行在哪个线程,主要看 Handler 绑定的 Looper 是在哪个线程创建和 loop 的,因为 Looper 的 next 方法最终会调用 Handler 的 handleMessage。

Handler 的内存泄漏

Handler 作为匿名内部类非静态内部类时,会持有外部 Activity 的引用,当 Activity 退出时,如果还存在着未处理的消息时,会导致 Activity 无法及时被回收,从而导致内存泄漏。

处理方式:

  1. 将 Handler 设置为 static 的,静态内部类不会持有外部类的引用。
  2. 在退出 Activity 时,移除所有未执行的 Message。
  3. 使用 WeakReference 来引用 Activity。

为什么主线程无须创建 Looper

系统自己为主线程创建了 Looper,并调用了 loop 方法,是在 ActivityThrad 类的 main 方法中创建的:

    public static void main(String[] args) {
        ......

        Looper.prepareMainLooper();

        ......
        Looper.loop();

        ......
    }

主线程 Looper 什么时候退出循环

在 ActivityThread 中也维护了一个 Handler,在其 handleMessage 中收到 EXIT_APPLICATION 消息时,会调用 mainLooper 的 quit 方法:

public void handleMessage(Message msg) {
            if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
            switch (msg.what) {
                case BIND_APPLICATION:
                    ......
                case EXIT_APPLICATION:
                    if (mInitialApplication != null) {
                        mInitialApplication.onTerminate();
                    }
                    Looper.myLooper().quit();
                    break;
                    ......
            }
    ......
}

sendMessage 和 postMessage 有什么区别

postMessage 会为 Message 设置一个 callback 回调,在 Handler 处理消息时,会先检查传递过来的 Message 是否已经设置了 callback,如果已经设置了,则将该消息交由 callback 处理,如果没有设置 callback 回调,会查看是否为 Handler 设置 callback 回调,如果 Handler 设置了,则消息交由 Handler 的 Callback.handleMessage 处理,如果 Handler 也没有设置 Callback,则交由 handlemessage 处理消息。

什么是 IdleHandler

在 Android 中,IdleHandler 接口用于实现一个回调机制,在系统处于空闲状态且没有待处理的用户界面事件时触发。IdleHandler 的目的是允许应用程序在系统不忙于其他活动时执行后台任务,例如预加载数据或更新用户界面。

在 MessageQueue 的 next 方法中,如果 MessageQueue 中没有消息,会进行阻塞,在阻塞之前,还会判断是否存在 IdleHandler,如果存在,就会去执行 IdleHandler 的 queueIdle 方法,如果不存在,才会阻塞队列。

需要注意的是,IdleHandler 不适用于长时间运行的任务或需要立即处理的任务,因为它可能会被不频繁地调用且持续时间很短。对于这些类型的任务,应使用其他机制,如线程或服务。

什么是 HandlerThread

名字包含 Handler,实际就是个 Thread,只不过内部实现了 Looper,无须我们手动创建而已。

Copyright© 2020-2022 li-xyz 冀ICP备2022001112号-1