Android之Handler原理解析与问题分享

news2024/9/25 9:30:56

一、Handler运行原理剖析

1.关系剖析图

如果把整个Handler交互看做一个工厂,Thread就是动力MessageQueue是履带Looper是转轴Loooper的loop方法就是开关,当调用loop方法时整个工厂开始循环工作,处理来自send和post提交到MessageQueue的消息,每处理完一个后由Handler的dispatch分发出去

2.代码走向剖析图

以上代码走向图无论send还是post,最终都是通过Handler的enqueueMessage方法将消息放到MessageQueue中,线程调用loop方法后循环从MessageQueue的next方法中获取消息并进行处理,每处理完一个后由Handler的dispatchMessage分发再通过handleMessage方法回调出去

二、Handler常见问题解答


1.一个线程可以有多少Handler?


无数个,因为在任何地方都可以直接new

2.一个线程可以有几个Looper?你如何保证只有那么多个?


一个,因为源码中已经做了这种判断,在线程被创建时源码中会通过ThreadLocal进行线程与Looper的绑定,通过一个Object[]使前者为key后者为value依次向后,当我们在调用Looper的prepare方法去创建其时,源码中会去调用ThreadLocal的get去判断,如存在抛出异常,不存在则调用set进行创建绑定;如果是主线程,则源码已经在ActivityThread的main方法中为我们创建好了,所以我们可以直接在主线程中new和使用,子线程中却需要调用prepare和loop进行使用

3.Handler为什么会发生内存泄漏?为什么其他的内部类没有这个问题?


因为Java虚拟机中内部类默认持有外部类的引用,当Activity如果在无感知的情况下被销毁时,Handler如果还在执行某些耗时操作时,所以就会产生内存泄漏;这跟Handler的原理有关,因为源码中消息池每一个Message都持有一个target(Handler)对象,而这个target(Handler)对象都持有外部类的引用如Activity,所以其他内部类没有这个问题
拓展:可以通过static+weak reference或Handler的remove对应方法解决

4.为何主线程可以直接new Handler?如果子线程想要new Handler需要做些什么?


因为主线程在ActivityThread的main方法中已经创建了Looper,所以主线程使用Handler时可以直接new;子线程使用Handler时需要调用Looper的prepare和loop方法才能进行使用,否则会抛出异常

5.如果子线程中需要维护一个Looper,当消息队列中没有消息时会发生什么问题?怎么解决?这样解决有什么作用?


当子线程run方法体的业务逻辑执行完时会走到loop处,导致子线程死锁;可以通过调用Looper提供的quitSafely方法,最终调用MessageQueue的quit方法,传一个true即可,如false则抛出异常,感兴趣的小伙伴可以去看看源码,提示主线程不允许退出;作用是移除所有没有处理的消息然后唤醒native锁并且释放资源

6.如果存在多个Handler往MessageQueue中添加数据,因为发送消息时各个Handler可能处于不同的线程,那源码内部是如何实现线程安全的?


因为在源码中可以发现MessageQueue的enqueueMessage方法在将消息推入时将入了同步代码块,在next去消息时也加入了同步代码块,所以保证了Handler消息的通讯是线程安全的

7.我们使用Message时应该怎么样去创建它更合理?


使用obtain去创建Message最合理

8.使用Handler的postDelay等延时方法后消息队列会有什么变化?


会根据delay时间去进行一个时间排序,通过遍历单链表把delay消息插入到合适的位置,然后通过nativePollOnce进行休眠,如有新消息进入则调用nativeWake唤醒,然后再计算时间差进行休眠,直到msg.when >= now为止

9.Looper死循环为什么不会导致应用卡死?


loop循环的取出消息并分发,无消息时会阻塞在next()方法中nativePollOnce()代码行,并释放CPU资源进入休眠,Android的绝大部分操作都是通过Handler机制来完成的,如果没有消息,则不需要程序去响应,就不会发生卡死。应用卡死指的是ANR一般是消息处理过程中耗时太长导致没有及时响应用户的操作

10.源码中是如何对Message做优化的?使用的是什么Java设计模式?


源码中对Message进行了池化策略的优化,避免过多的创建Message对象;享元模式

        

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1489705.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Nodejs 第四十五章(redis发布订阅+事务)

发布订阅 发布-订阅是一种消息传递模式,其中消息发布者(发布者)将消息发送到频道(channel),而订阅者(订阅者)可以订阅一个或多个频道以接收消息。这种模式允许消息的解耦&#xff0…

006-CSS-常见问题汇总

常见问题汇总 1、伪元素与伪类2、偏门但好用的样式3、文字溢出三个点展示4、空白折叠问题5、文字的垂直居中6、 Vue项目中 在父组件中修改子组件样式7、BFC 概念7.1、兄弟元素外边距合并7.2、父子元素外边距塌陷 8、box-sizing8.1、box-sizing: border-box8.2、box-sizing: con…

11. Nginx进阶-HTTPS

简介 基本概述 SSL SSL是安全套接层。 主要用于认证用户和服务器,确保数据发送到正确的客户机和服务器上。 SSL可以加密数据,防止数据中途被窃取。 SSL也可以维护数据的完整性,确保数据在传输过程中不被改变。 HTTPS HTTPS就是基于SSL来…

1.1_2 性能指标——速率、带宽、吞吐量

文章目录 1.1_2 性能指标——速率、带宽、吞吐量(一)速率(二)带宽(三)吞吐量 1.1_2 性能指标——速率、带宽、吞吐量 (一)速率 速率即数据率或称数据传输率或比特率。 速率就是“快…

【代码】Python3|无GUI环境中使用Seaborn作图的学习路线及代码(阴影折线图)

我有个需求是需要画图,让GPT帮我生成了一下学习计划。 学习路线依照GPT的来的,使用的Prompt工具是https://github.com/JushBJJ/Mr.-Ranedeer-AI-Tutor。 文章目录 PrerequisiteMain Curriculum1.1 Seaborn介绍Seaborn基础保存图形为文件练习 1.2 单变量数…

瑞芯微RK3588 C++部署Yolov8检测和分割模型

最近这一个月在研究国产瑞芯微板子上部署yolov8的检测和分割模型,踩了很多坑,记录一下部署的过程和遇到的一些问题: 1 环境搭建 需要的环境和代码主要包括: (1)rknn-toolkit2-1.5.2:工具链&am…

uniapp开发android原生插件

一、下载原生开发SDK Android 离线SDK - 正式版 | uni小程序SDK (dcloud.net.cn)、 https://nativesupport.dcloud.net.cn/AppDocs/download/android.html 将开发uniappa原生android的插件解压到ben本地目录,目录结构如下: 接下就可以使用 UniPlugin-Hel…

12 状态优先级

概念 cpu需要执行很多进程,有很多进程排在队列中,每个进程加载后运行一定的时间段,然后切换下一个进程。cpu如何判断进程需不需要加载,什么时候加载,依靠进程的状态和优先级属性来判断,进程调度&#xff0…

Node.js与Webpack笔记(一)

这里使用的16.19.0版本,官网和github没找到,去黑马2023年课程里找 篇幅较大会卡,此篇幅不写Webpack部分,留着下一篇 初识 1.什么是Node.js? Node.js 是一个独立的 JavaScript 运行环境,能独立执行 JS 代码&#xff…

A/D转换

硬件电路模型 模数转换代码 main.c #include <REGX52.H> #include "LCD1602.h" #include "Delay.h" #include "XPT2046.h"unsigned int ADValue; int main(){LCD_Init();LCD_ShowString(1,1,"ADJ NTC RG");while(1){ADValue …

iOS 17.0 UIGraphicsBeginImageContextWithOptions 崩溃处理

在升级到iOS17后你会发现&#xff0c;之前版本运行的很好&#xff0c;这个版本突然会出现一个运行闪退。报错日志为*** Assertion failure in void _UIGraphicsBeginImageContextWithOptions(CGSize, BOOL, CGFloat, BOOL)(), UIGraphics.m:410 跟踪到具体的报错位置如下所示&a…

redis09 集群(cluster)

思维草图 为什么要使用集群 单台redis内存容量的限制单台redis并发写量太大有性能瓶颈 redis集群认识 redis集群是对redis的水平扩容&#xff0c;即启动N个redis节点&#xff0c;将整个数据分布存储在这个N个节点中&#xff0c;每个节点存储总数据的1/N。 如下图&#xff1…

win11部署自己的privateGpt(2024-0304)

什么是privateGpt? privategpt开源项目地址 https://github.com/imartinez/privateGPT/tree/main 官方文档 https://docs.privategpt.dev/overview/welcome/welcome PrivateGPT是一个可投入生产的人工智能项目&#xff0c;利用大型语言模型&#xff08;LLMs&#xff09;的…

Windows安装SSH教程

Windows安装SSH教程 一、SSH1.SSH简介2.SSH功能3.SSH验证3.1 第一种级别&#xff08;基于口令的安全验证&#xff09;3.2 第二种级别&#xff08;基于密匙的安全验证&#xff09; 4.SSH层次4.1 传输层协议 [SSH-TRANS]4.2 用户认证协议 [SSH-USERAUTH]4.3 连接协议 [SSH-CONNEC…

场景问题: VisualVM工具Profiler JDBC不是真实执行的SQL

1. 问题 诡异的问题表象&#xff1a; 前端反馈分页接口的Total字段一直为0 使用Visualvm中的 Profiler 注入到应用后&#xff0c;查看JDBC监控得到了分页接口执行的SQL&#xff0c;复制出来执行是55. 此时还没有注意到 IN 的范围中有一个特别的值 NULL &#x1f928; 2. 排查…

【运维必学】2.零基础搞IT运维之服务器操作系统基础知识储备

微信改版了&#xff0c;现在看到我们全凭缘分&#xff0c;为了不错过【全栈工程师修炼指南】重要内容及福利&#xff0c;大家记得按照上方步骤设置「接收文章推送」哦~ 文章目录&#xff1a; 温馨提示&#xff1a;作者最近开通的知识星球&#xff0c;全栈系列从门到实践教程将会…

QT----写完的程序打包为APK在自己的手机上运行

目录 1、qt安装android组件2、打开qt配置Android 环境3、手机打开开发者模式&#xff0c;打开usb调试&#xff0c;连接电脑4、运行代码 1、qt安装android组件 qtcreater–工具-QTMaintenaceTool-startMaintenaceTool—登陆—添加或修改组件—找到android&#xff0c;安装 若是…

Windows环境MySQL全量备份+增量备份

目录 一、环境准备 1.1.安装MySQL 1.2.添加log-bin日志配置 二、创建测试数据库和表 2.1.创建测试数据库 2.2.创建测试数据表 三、全量备份恢复数据库 3.1.全量备份数据库 3.2全量恢复数据库 四、增量备份恢复数据库 4.1.增量备份数据库 4.2.增量恢复数据库 五、…

抽象步骤条(2.0版本)

vue3 router ele-plus 猜猜看为什么使用组件库&#xff01; 他呀的&#xff01;查看密码要自己写&#xff0c;验证信息也要自己写&#xff0c;所以说会用组件库会轻松一点&#xff0c;&#xff0c;&#xff0c; 代码如下 <template><div class"main"&g…

自动化构建平台(五)之Jenkins初始化配置以及插件安装操作

文章目录 前言一、安装必要插件二、系统参数配置三、全局工具配置总结 前言 上一篇我们介绍了Jenkins的安装和登录等相关操作&#xff0c;今天给大家介绍登录Jenkins后的一些初始化配置和插件安装的操作。因为如果要使用Jenkins来进行代码构建&#xff0c;必须先安装相关的插件…