Handler 知识点梳理:Handler、Looper 以及

2022-08-26  本文已影响0人  程序老秃子

前言

Handler、Looper以及Message之间的关系,概括性来说,Looper负责的是创建一个MessageQueue对象,然后进入到一个无限循环体中不断取出消息,而这些消息都是由一个或者多个Handler进行创建处理

Messagequeue 的数据结构是什么

基础数据结构中 “先进先出” 的一种数据结构

Handler post 原理

消息是通过 MessageQueen 中的 enqueueMessage()方法加入消息队列中的,并且它在放入中就进行好排序,链表头的延迟时间小,尾部延迟时间最大

handler.postDelay()的实现是通过MessageQueue中执行时间顺序排列,消息队列阻塞和唤醒的方式结合实现的;如果真的是通过延迟将消息放入到 MessageQueen中,那放入多个延迟消息就要维护多个定时器

Android 消息机制的简介

在 Android 中使用消息机制,我们首先想到的就是 Handler;没错,Handler是 Android 消息机制的上层接口;Handler 的使用过程很简单,通过它可以轻松地将一个任务切换到Handler所在的线程中去执行。通常情况下,Handler的使用场景就是更新UI

在子线程中,进行耗时操作,执行完操作后,发送消息,通知主线程更新 UI;这便是消息机制的典型应用场景。我们通常只会接触到 Handler 和 Message 来完 成消息机制,其实内部还有两大助手来共同完成消息传递

消息机制的模型 消息机制主要包含: MessageQueue,Handler和Looper这三大部分,以及Message,下面我们一一介绍

消息机制的架构

消息机制的运行流程:在子线程执行完耗时操作,当 Handler 发送消息时,将会 调用MessageQueue.enqueueMessage,向消息队列中添加消息

当通过Looper.loop 开启循环后,会不断地从线程池中读取消息,即调用 MessageQueue.next,然后 调用目标 Handler(即发送该消息的 Handler)的 dispatchMessage 方法传递消息,然后返回到 Handler 所在线程,目标 Handler 收到消息,调用 handleMessage方法,接收消息,处理消息

MessageQueue,Handler 和 Looper 三者之间的关系:每个线程中只能存在一个 Looper,Looper 是保存在 ThreadLocal 中的。主线程(UI 线程)已经创建了一个 Looper,所以在主线程中不需要再创建 Looper,但是在其他线程中需要创建 Looper

每个线程中可以有多个 Handler,即一个Looper 可以处理来自多个 Handler的消息;Looper 中维护一个MessageQueue,来维护消息队列,消息队列中的 Message可以来自不同的 Handler

我们可以使用 Handler 发送并处理与一个线程关联的 Message 和 Runnable ;(注意:Runnable 会被封装进一个 Message,所以它本质上还是一个 Message ) 每个 Handler 都会跟一个线程绑定,并与该线程的 MessageQueue 关联在一起, 从而实现消息的管理以及线程间通信

Handler 引起的内存泄露原因以及最佳解决方案

Handler 允许我们发送延时消息,如果在延时期间用户关闭了 Activity,那么该 Activity 会泄露

这个泄露是因为 Message 会持有 Handler,而又因为 Java 的特性,内部类会 持有外部类,使得 Activity 会被 Handler 持有,这样最终就导致 Activity 泄露

解决该问题的最有效的方法是:将 Handler 定义成静态的内部类,在内部持有 Activity 的弱引用,并及时移除所有消息

示例代码如下:

private static class SafeHandler extends Handler {
private WeakReference<HandlerActivity> ref;
public SafeHandler(HandlerActivity activity) {
this.ref = new WeakReference(activity);
}
@Override
public void handleMessage(final Message msg) {
HandlerActivity activity = ref.get();
if (activity != null) {activity.handleMessage(msg);
}
}}

并且再在 Activity.onDestroy() 前移除消息,加一层保障:

@Overrideprotected void onDestroy() {
safeHandler.removeCallbacksAndMessages(null);
super.onDestroy();
}

这样双重保障,就能完全避免内存泄露了。注意:单纯的在 onDestroy 移除消息并不保险,因为 onDestroy 并不一定执行

Android UI 是线程不安全的,如果在子线程中尝试进行 UI 操作,程序就有可能 会崩溃

相信大家在日常的工作当中都会经常遇到这个问题,解决的方案应该也 是早已烂熟于心,即创建一个 Message 对象,然后借助 Handler 发送出去,之 后在 Handler 的 handleMessage()方法中获得刚才发送的 Message 对象,然 后在这里进行 UI 操作就不会再出现崩溃了

在主线程中可 以直接创建 Handler 对象,而在子线程中需要先调用 Looper.prepare()才能创 建 Handler 对象

有关 Handler 的知识点就到这里了, 有需要学习更多关于 Handle 知识点的同学,可以 私信 发送 “进阶” 即可 获取一份 学习笔记 ,相信能够帮助大家 查漏补缺

资料部分内容展示如下:

《Handler 机制之 Thread》

《Handler机制之ThreadLocal》

完整版PDF文档获取方式: 私信 发送 “进阶” 即可 免费获取

对于程序员来说,要学习的知识内容、技术有太多太多,要想不被环境淘汰就只有不断提升自己,从来都是我们去适应环境,而不是环境来适应我们

技术是无止境的,你需要对自己提交的每一行代码、使用的每一个工具负责,不断挖掘其底层原理,才能使自己的技术升华到更高的层面

Android 架构师之路还很漫长,与君共勉

上一篇 下一篇

猜你喜欢

热点阅读