Android Handler机制(二) Handler 实现原理
一. 前言
接上一篇文章为什么设计Handler , 我们来继续讲解一下Handler的实现原理, 俗话说一个好汉三个帮, 接下来一步一步引入各个主角,并说明它们在Handler机制中扮演的角色和作用.
二. Handler实现原理
首先我们先确定一个结论: 使用 Handler 是希望它被实例化在哪个线程,哪个线程就是消息的接收端,在其他线程内发送消息时,调用的还是这个 Handler对象的 sendMessage(xx).
结论支撑可以看之前的博客: HandlerThread源码理解
图一:

图二:
我们再来看一张关于多线程之间的通信图

这个图也可以得出如下结论:Handler 接收消息端是线程独立的,不管 handler的引用在哪个线程发送消息都会传回自己被实例化的那个线程中.
但显而易见的是 Handler 不可能是线程独立的,因为它的引用会在别的线程作为 消息的发送端,也就是说它本身就是多线程共享的引用,不可能独立存在于某个线程内.
所以!Handler 需要一个独立存在于线程内部且私有使用的类帮助它接收消息! 这个类就是 Looper!
三. Looper -线程独立
通过上节我们已经知道设计Looper就是为了辅助Handler接收消息且仅独立于线程内部。那如何才能实现线程独立的呢?
Java 早就考虑到了这一点,早在 JDK 1.2 的版本中就提供 ThreadLocal 这么一个工具类来帮助开发者实现线程独立。
那为什么要理解ThreadLocal呢? 因为Looper源码中有这一段代码
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();private static void prepare(boolean quitAllowed) {if (sThreadLocal.get() != null) {throw new RuntimeException("Only one Looper may be created per thread");}sThreadLocal.set(new Looper(quitAllowed));}
这样子就实现了Looper线程独立.
理解ThreadLocal 原理需要先掌握一下 java强软弱虚引用基本概念, 参考笔者之前写的博客:
java 强软弱虚引用和ThreadLocal工作原理
到这里就可以支撑这个结论:有了ThreadLocal 之后我们只需要把 Looper 存进去就能实现线程独立了.
到这里再梳理一下流程:
1. Handler 引用可以多线程间共享。
2. 当 Handler 对象在其他线程发送消息时,通过 Handler 的引用找到它所在线程的 Looper 接收消息。
3. Looper 负责接收消息再分发给 Handler 的接收消息方法
这里我们再提一个问题: 如果多个线程同时使用一个 Handler 发消息,Looper 该怎么办?给接收消息的方法上锁吗?
回答: 显然不能这样做
解决方法呢?
google工程师就设计出MessageQueue来解决这个问题.
四. MessageQueue - 多线程同时发消息
为了防止多个线程同时发送消息 Looper 一下着忙不过来,于是设计一个 MessageQueue 类以队列的方式保存着待发送的消息,这样 Looper 就可以一个个 的有序的从 MessageQueue 中取出消息处理了。 既然 MessageQueue 是为 Looper 服务的,而 Looper 又是线程独立的,所以 MessageQueue 也是线程独立的.
MessageQueue 看名字应该是个队列结构,队列的特点是什么?先进先出,一般在队尾增加数据,在队首进行取数据或者删除数据。那Handler中的消息似乎也满足这样的特点,先发的消息肯定就会先被处理。但是,Handler中还有比较特殊的情况,比如延时消息。
延时消息的存在就让这个队列有些特殊性了,并不能完全保证先进先出,而是需要根据时间来判断,所以Android中采用了链表的形式来实现这个队列,也方便了数据的插入.
数据结构中队列和链表的基本概念理解,请参考笔者博客:
五. 总结
现在我们已经知道为了完成异步消息功能需要有 Handler 家族的四位成员共同合作:
Handler: 负责发送消息,为开发者提供发送消息与接收消息的方法。
Message: 消息载体,负责保存消息具体的数据。
MessageQueue:消息队列,以队列形式保存着所有待处理的消息, 原理实现采用的是链表.
Looper:消息接受端,负责不断从 MessageQueue 中取出消息分发给 Handler 接受消息端
这四位成员哪个都不是平白无故出现的。因为要规范化消息传递格式而定义了 Message;
为了实现消息接收端只存在线程内部私有化使用而定义了 Looper;
为 了解决多线程同时发送数据 Looper 分发消息处理时会产生的问题而设计 MessageQueue 队列化消息。
到这里你应该知道了 Handler 家族四位成员各自负责的是什么工作,以及他们自身的特点特殊性,比如 Handler 是线程间共享的而 Looper 是线程独立的, MessageQueue 跟 Looper 又是一对一的。
工作图:

相关文章:
Android Handler机制(二) Handler 实现原理
一. 前言 接上一篇文章为什么设计Handler , 我们来继续讲解一下Handler的实现原理, 俗话说一个好汉三个帮, 接下来一步一步引入各个主角,并说明它们在Handler机制中扮演的角色和作用. 二. Handler实现原理 首先我们先确定一个结论: 使用 Handler 是希望它被实例化在哪个线程&a…...
Elasticsearch教程(19) 详解mapping之keyword
Elasticsearch已升级,新版Elasticsearch keyword博客参考下面这篇【Elasticsearch教程8】Mapping字段类型之keyword_elasticsearch的keyword_亚瑟弹琴的博客-CSDN博客 1 前言 本文基于ES7.6,如果是之前版本,是有区别的。 ES支持的字段类型很…...
LeetCode算法复杂度分析(时间复杂度空间复杂度)
文章目录前言时间复杂度1.概述2.大O记法3.常见类型空间复杂度1.概述2.常见类型典型算法的复杂度分析1.递归算法2.哈希表前言 我们知道,研究算法的最终目的就是如何花更少的时间,如何占用更少的内存去完成相同的需求。 时间复杂度 1.概述 我们要计算算…...
Android OpenCV(七十三):吊打高斯模糊的StackBlur Android 实践
前言 OpenCV 4.7.0 2022年12月28日Release,ChangeLog中提到 Stackblur algorithm implementation. Stackblur是一种高斯模糊的快速近似,由Mario Klingemann发明。其计算耗时不会随着kernel size的增大而增加,专为大kernel size的模糊滤波场景量身定制。 使用建议:当kerne…...
4.排序算法之一:冒泡排序
排序算法稳定性假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次序保持不变,即在原序列中,r[i]r[j],且r[i]在r[j]之前,而在排序后的序列中,r[…...
python自学之《21天学通Python》(16)——第19章 用Pillow库处理图片
Pillow是Python2.X时代比较流行的Python ImagingLibrary(简称Pillow)图像处理库的分支,并修复了一些bug。Pillow提供了对Python3的支持,为Python3解释器提供了图像处理的功能。和Pillow库一样提供了广泛的文件格式支持、高效的内部…...
发布依赖到maven仓库
maven中央仓库是一个开放的仓库,所以我们也可以把自己开发的jar推送到远程仓库,这样可以直接引入pom依赖使用我们的库。 准备工作 ● 需要一个github账号(程序员必备) ● 网络代理(涉及到的网站通常没版本在国内直接访…...
Laravel-admin之自定义操作日志
laravel-admin是封装性极好的框架,自带的就有操作日志的记录,但是对于非开发人员可能看不懂这个日志,所以就想着给修改一下,以谁修改了什么,谁删除了什么,谁审核了什么,谁添加了什么类似&#x…...
用Python做了一个法律查询小工具,非常好用
用Python做了一个法律查询小工具,非常好用效果展示准备工作不会的话可以点我直达代码和视频讲解,我都准备好了主要代码哈喽兄弟,今天给大家分享一个Python tkinter制作法律查询小工具。 光爬虫大家也只能自己用用,就算打包了exe&…...
工作篇:触摸屏原理介绍
一、触摸屏概述 触摸屏作为一种新的输入设备,它是目前最简单、方便、自然的一种人机交互方式。 当接触了屏幕上的图形按钮时,屏幕上的触觉反馈系统可根据预先编程的程式驱动各种连结装置,可用以取代机械式的按钮面板,并借由液晶…...
Ep_操作系统面试题-操作系统的分类
答案 单体系统 整个操作系统是以程序集合来编写的,链接在一块形成一个二进制可执行程序,这种系统称为单体系统。 分层系统 每一层都使用下面的层来执行其功能。 微内核 微内核架构的内核只保留最基本的能力,把一些应用放到了用户空间 客户-…...
iframe或document监听滚动事件不起作用
有时候我们会遇到监听iframe或document的滚动事件不起作用的情况,在排除代码写错的情况下,我们应该考虑此时的document是否可以滑动。 1、为什么document不能监听滑动? 就很奇怪,明明页面时有滚动条的,为什么说document不可滑动…...
基频估计算法简介
基频估计算法 F0 estimate methods 估计F0的方法可以分为三类:基于时域、基于频域、或混合方法。本文详细介绍了这些方法。 所有的算法都包含如下三个主要步骤: 1.预处理:滤波,加窗分帧等 2.搜寻:可能的基频值F0(候选…...
linux修改DNS 系统版本Kylin V10桌面版
配置DNS在银河麒麟桌面操作系统V10 SP1 中修改DNS信息,直接修改/etc/resolv.conf文件中的DNS信息,不能生效。应该参考如下步骤:一、首先修改 /etc/systemd/resolved.conf文件,在其中添加DNS信息在终端中执行以下命令:s…...
如何使用 AWS Lambda 运行 selenium
借助 AWS Lambda 运行 selenium 来爬取网络数据。 简介 与手动从网站收集数据相比,爬虫可以为我们节省很多时间,对于爬虫的每次请求而言,这相当于 AWS Lambda 的每次函数的运行。 AWS Lambda 是一种将脚本部署到云的简单且价格低廉的服务&…...
认识Cesium旋转大小变量
前文代码中有如下;矩阵乘以旋转大小,还放入mat; Cesium.Matrix4.multiply(mat, rotationX, mat); 初看以为rotationX是一个数值,因为矩阵可以和数相乘; 但是看它的代码,rotationX是由一长串代码获得的&a…...
异响加持、吐槽声不断,小鹏G9难解困局
小鹏汽车的烦恼就好比红尘中的三千青丝,小鹏G9“惊魂48小时”的恐慌还未平息,车门异响等问题就已经层出不穷,再次将小鹏汽车推上风口浪尖。 可以毫不客气的说,G9承载着小鹏汽车盈利的希望,但在原本处于上升之势的G9却…...
【react】react18的学习
一、安装 $ create-react-app [Project name]默认支持sass 二、核心依赖 react:react 核心 react-dom:用于开发渲染web 应用; react-scripts:封装webpack服务; "start": "react-scripts start&quo…...
Ep_操作系统面试题-什么是线程,线程和进程的区别
1. 一个进程中可以有多个线程,多个线程共享进程的堆和方法区 (JDK1.8 之后的元空间),但是每个线程有自己的程序计数器、虚拟机栈和 本地方法栈。 2.进程是资源分配的最小单位,线程是CPU调度的最小单位 视频讲解: https://edu.csdn.net/course/detail/38090 点我…...
最流行的自动化测试工具,总有一款适合你(附部分教程)
前言 在自动化测试领域,自动化工具的核心地位毋庸置疑。本文总结了最顶尖的自动化测试工具和框架,这些工具和框架可以帮助组织更好地定位自己,跟上软件测试的趋势。这份清单包含了开源和商业的自动化测试解决方案。 1)Selenium …...
基于算法竞赛的c++编程(28)结构体的进阶应用
结构体的嵌套与复杂数据组织 在C中,结构体可以嵌套使用,形成更复杂的数据结构。例如,可以通过嵌套结构体描述多层级数据关系: struct Address {string city;string street;int zipCode; };struct Employee {string name;int id;…...
深度学习在微纳光子学中的应用
深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向: 逆向设计 通过神经网络快速预测微纳结构的光学响应,替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…...
基于Uniapp开发HarmonyOS 5.0旅游应用技术实践
一、技术选型背景 1.跨平台优势 Uniapp采用Vue.js框架,支持"一次开发,多端部署",可同步生成HarmonyOS、iOS、Android等多平台应用。 2.鸿蒙特性融合 HarmonyOS 5.0的分布式能力与原子化服务,为旅游应用带来…...
C++ 基础特性深度解析
目录 引言 一、命名空间(namespace) C 中的命名空间 与 C 语言的对比 二、缺省参数 C 中的缺省参数 与 C 语言的对比 三、引用(reference) C 中的引用 与 C 语言的对比 四、inline(内联函数…...
CocosCreator 之 JavaScript/TypeScript和Java的相互交互
引擎版本: 3.8.1 语言: JavaScript/TypeScript、C、Java 环境:Window 参考:Java原生反射机制 您好,我是鹤九日! 回顾 在上篇文章中:CocosCreator Android项目接入UnityAds 广告SDK。 我们简单讲…...
【C语言练习】080. 使用C语言实现简单的数据库操作
080. 使用C语言实现简单的数据库操作 080. 使用C语言实现简单的数据库操作使用原生APIODBC接口第三方库ORM框架文件模拟1. 安装SQLite2. 示例代码:使用SQLite创建数据库、表和插入数据3. 编译和运行4. 示例运行输出:5. 注意事项6. 总结080. 使用C语言实现简单的数据库操作 在…...
(转)什么是DockerCompose?它有什么作用?
一、什么是DockerCompose? DockerCompose可以基于Compose文件帮我们快速的部署分布式应用,而无需手动一个个创建和运行容器。 Compose文件是一个文本文件,通过指令定义集群中的每个容器如何运行。 DockerCompose就是把DockerFile转换成指令去运行。 …...
分布式增量爬虫实现方案
之前我们在讨论的是分布式爬虫如何实现增量爬取。增量爬虫的目标是只爬取新产生或发生变化的页面,避免重复抓取,以节省资源和时间。 在分布式环境下,增量爬虫的实现需要考虑多个爬虫节点之间的协调和去重。 另一种思路:将增量判…...
CSS设置元素的宽度根据其内容自动调整
width: fit-content 是 CSS 中的一个属性值,用于设置元素的宽度根据其内容自动调整,确保宽度刚好容纳内容而不会超出。 效果对比 默认情况(width: auto): 块级元素(如 <div>)会占满父容器…...
A2A JS SDK 完整教程:快速入门指南
目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库ÿ…...
