Handler相关问题

news2024/10/7 8:30:20

Handler相关问题

  • 1、设计 Handler 的初衷?
  • 2、一个线程有几个 Looper?几个 Handler?
  • 3、Handler 内存泄漏原因? 以及最佳解决方案?
  • 4、为何主线程可以 new Handler?如果想要在子线程中 new Handler 要做些什么准备?
  • 5、子线程中维护的 Looper,消息队列无消息的时候的处理方案是什么?有什么用?
  • 6、既然可以存在多个 Handler 往 MessageQueue 中添加数据(发消息时各个Handler 可能处于不同线程),那它内部是如何确保线程安全的?
  • 7、我们使用 Message 时应该如何创建它?
  • 8、Looper 死循环为什么不会导致应用卡死?

1、设计 Handler 的初衷?

Handler 就是针对 Android 系统中与 UI 线程通信而专门设计的多线程通信机制

2、一个线程有几个 Looper?几个 Handler?

一个 Thread 只能有一个 Looper,一个 MessageQueue,可以有多个 Handler。
以一个线程为基准,他们的数量级关系是: Thread(1) : Looper(1) :MessageQueue(1) : Handler(N)。

3、Handler 内存泄漏原因? 以及最佳解决方案?

泄露原因:
Handler 允许我们发送延时消息,如果在延时期间用户关闭了 Activity,那么该 Activity 会泄露。 这个泄露是因为 Message 会持有 Handler,而又因为 Java 的特性,内部类会持有外部类,使得 Activity 会被 Handler持有,这样最终就导致 Activity 泄露。


解决方案

  1. 最直接的思路就是避免使用非静态内部类。使用 Handler 的时候,放在一个新建的文件中来继承 Handler 或者使用静态的内部类来替代。静态内部类不会隐含的持有外部类的引用,因此这个 activity 也就不会出现内存泄漏问题。
  2. 弱引用(WeakReference);如果你需要在 Handler 内部调用外部 Activity 的方法,你可以让这个 Handler 持有这个 Activity 的弱引用,这样便不会出现内存泄漏的问题了。
public class SampleActivity extends Activity {
   /**
    * 弱引用的方式
    */
   private static class MyHandler extends Handler {
       private final WeakReference<SampleActivity> mActivity;

       public MyHandler(SampleActivity activity) {
           mActivity = new WeakReference<SampleActivity>(activity);
       }

       @Override
       public void handleMessage(Message msg) {
           SampleActivity activity = mActivity.get();
           if (activity != null) {
               //to Something
           }
       }
   }
}
  1. 静态,对于匿名类 Runnable,我们同样可以设置成静态的,因为静态内部类不会持有外部类的引用。
//定义成 static 的,因为静态内部类不会持有外部类的引用
private final MyHandler mHandler=new MyHandler(this);
private static final Runnable sRunnable=new Runnable(){
   @Override
   public void run(){//to something
   };
   @Override
   protected void onCreate(Bundle savedInstanceState){
       super.onCreate(savedInstanceState);
       mHandler.postDelayed(sRunnable,1000*60*10);
       finish();
   }
}

4、为何主线程可以 new Handler?如果想要在子线程中 new Handler 要做些什么准备?

每一个 handler 必须要对应一个 looper,主线程会自动创建 Looper 对象,不需要我们手动创建,所以主线程可以直接创建 handler。
在 new handler 的时候没有传入指定的 looper 就会默认绑定当前创建 handler 的线程的 looper,如果没有 looper 就报错。
因为在主线程中,Activity 内部包含一个 Looper 对象,它会自动管理 Looper,处理子线程中发送过来的消息。而对于子线程而言,没有任何对象帮助我们维护Looper 对象,所以需要我们自己手动维护。
所以要在子线程开启 Handler 要先创建 Looper,并开启 Looper 循环


如果在子线程中创建了一个 Handler,那么就必须做三个操作:

  1. prepare();
  2. loop();
  3. quit();

5、子线程中维护的 Looper,消息队列无消息的时候的处理方案是什么?有什么用?

在 Handler 机制里面有一个 Looper,在 Looper 机制里面有两个函数,叫做quitSafely()和 quit()函数,这两个函数是调用的 MessageQueue 的 quit();
再进入到 MessageQueue 的 quit()函数,它会 remove 消息,把消息队列中的全部消息给干掉。把消息全部干掉,也就释放了内存。而在 quit()函数的最后一行,有一个 nativeWake()函数。这个函数的调用,就会叫醒等待的地方,醒来之后,就接着往下执行。
往下执行后,发现 Message msg = mMessages; 是空的,没有消息,nextPollTimeoutMillis 复位;如果消息队列正在处于退出状态返回 null,调用 dispose();释放该消息队列。这个时候 Looper 就结束了(跳出了死循环),则达成了第二个作用:释放线程

6、既然可以存在多个 Handler 往 MessageQueue 中添加数据(发消息时各个Handler 可能处于不同线程),那它内部是如何确保线程安全的?

这里主要关注 MessageQueue 的消息存取即可,看源码内部的话,在往消息队列里面存储消息时,会拿当前的 MessageQueue 对象作为锁对象,这样通过加锁就可以确保操作的原子性和可见性了。
消息的读取也是同理,也会拿当前的 MessageQueue 对象作为锁对象,来保证多线程读写的一个安全性。
在这里插入图片描述

7、我们使用 Message 时应该如何创建它?

创建的它的方式有两种:
一种是直接 new 一个 Message 对象
另一种是通过调用 Message.obtain() 的方式去复用一个已经被回收的Message


当然日常使用者是推荐使用后者来拿到一个 Message,因为不断的去创建新对象的话,可能会导致垃圾回收区域中新生代被占满,从而触发 GC。

8、Looper 死循环为什么不会导致应用卡死?

Launch 桌面的图标第一次启动 Activity 时,会最终走到 ActivityThread 的 main 方法,在 main 方法里面创建 Looper 和 MessageQueue 处理主线程的消息,然后Looper.loop()方法进入死循环,我们的 Activity 的生命周期都是通过 Handler 机制处理的,包括 onCreate、onResume 等方法,下面是 loop 方法循环。


主线程的主要方法就是消息循环,一旦退出消息循环,那么你的应用也就退出了,Looer.loop()方法可能会引起主线程的阻塞,但只要它的消息循环没有被阻塞,能一直处理事件就不会产生 ANR 异常。


造成 ANR 的不是主线程阻塞,而是主线程的 Looper 消息处理过程发生了任务阻塞,无法响应手势操作,不能及时刷新 UI。
阻塞与程序无响应没有必然关系,虽然主线程在没有消息可处理的时候是阻塞的,但是只要保证有消息的时候能够立刻处理,程序是不会无响应的。


总结:应用卡死压根与这个 Looper 没有关系,应用在没有消息需要处理的时候,它是在睡眠,释放线程;卡死是 ANR,而 Looper 是睡眠。

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

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

相关文章

docker是怎么决定容器内容存储到哪个目录的?(存储驱动决定的)(乱七八糟的)(df -Th查看目录文件系统类型、查看文件系统类型)

文章目录 docker是怎么决定容器内容存储到哪个目录的&#xff1f;docker对我/var这个目录有没有什么要求&#xff0c;比如要求它的文件系统是指定的类型如果我Docker的默认存储驱动是overlay2&#xff0c;但是我/var目录的文件系统不是overlay2&#xff0c;这没影响吗&#xff…

人工智能MINIST手写数字识别之MINIST概念

MNIST是一个简单的视觉计算数据集,它是像下面这样手写的数字图片: MNIST 每张图片还额外有一个标签记录了图片上数字是几,例如上面几张图的标签就是:5、0、4、1。 MINIST数据 MINIST的数据分为2个部分:55000份训练数据(mnist.train)和10000份测试数据(mnist.test)。这…

Doo Prime 德璞资本:初学者必看!期货是怎么交易的四大技能

期货交易是一种金融衍生品交易&#xff0c;是指在未来某个约定的时间和价格上&#xff0c;按照合约规定的标的物进行买卖的交易方式。它是一种非常重要的投资方式&#xff0c;因为它可以帮助投资者在风险管理方面更好地掌握市场。 期货的交易方式非常多样化&#xff0c;尤其是…

【51单片机】:串口通信控制LED亮灭任务

学习目标&#xff1a; 使用51单片机的串口通信&#xff0c;当串口通信助手 发送字符串 on led开启 发送字符串 off led关闭 并且串口助手实时返回 发送的字符串 学习内容&#xff08;代码&#xff09;&#xff1a; 第一种方法&#xff0c;使用数组依次判断接收到的字…

凝聚青年力量,打造数字化人才队伍

当代青年人勇于探索、敢于创新、勤于变革&#xff0c;积极承担社会责任。这与ABeam倡导的「Build Beyond As One.™」的品牌理念不谋而合。ABeam的青年员工是未来社会的中坚力量&#xff0c;也正用他们的青春能量助力ABeam在中国的发展。 01 新兴青年力量 对ABeam而言&#…

走进工厂,认识静电测试仪器——使用方法和注意事项

随着科技的不断发展,静电测试仪器越来越多地被人们所使用。但是有些人对静电测试仪的使用方法和注意事项还不是很了解。 1&#xff1a;静电测试仪器的基本知识 静电测试仪器是一种用来测量电源电压、电流和电容器的材料。通常&#xff0c;静电测试仪器由一个电阻器或一组绝缘…

R语言丨Pheatmap绘制基因表达量热图

Pheatmap绘制基因表达量热图 论文中展示基因表达量变化通常使用热图&#xff0c;今天分享一个快速绘制不同基因在各处理下表达量变化的方法&#xff0c;使用R语言中pheatmap包&#xff0c;它可以用于可视化数据集中的数值&#xff0c;以便更好地理解数据之间的关系和模式。 …

STM32单片机WIFI教室灯光控制系统人数自动灯光温度时间

实践制作DIY- GC0135-WIFI教室灯光控制系统 一、功能说明&#xff1a; 基于STM32单片机设计-WIFI教室灯光控制系统 二、功能介绍&#xff1a; 电路&#xff1a;STM32F103C最小系统板DS18B20温度传感器LCD1602显示器ESP8266WIFI模块4个红外槽型光电传感器3个LED灯多个按键蜂鸣…

Linux内核模块编程

访问【WRITE-BUG数字空间】_[内附完整源码和文档] 1 总体设计思路 Linux内核是单体式结构&#xff0c;相对于微内核结构而言&#xff0c;其运行效率高&#xff0c;但是系统的可维护性和可扩展性较差。为此&#xff0c;Linux提供了内核模块&#xff08;module&#xff09;机制&…

腾讯轻量服务器python3.6升级到python3.9.9

由于不了解linux&#xff0c;要配合宝塔的查看文件&#xff0c;这样轻松很多 用得到的2个基本命令: sudo 管理员方式运行&#xff08;我照着网上方法试几次安装都没成功&#xff0c;就是开头没加这句&#xff09; pwd 显示当前的目录 第1步 下载新python sudo wget https://ww…

用写代码的方式画图-试下PlantUML吧 | 京东云技术团队

1 序言 所谓一图胜千言&#xff0c;大家平日在工作中编写文档时&#xff0c;往往都需要画各种图来表达中心思想&#xff0c;比如流程图、时序图、UML 图&#xff0c;很多人选择使用 Axure 、PrecessOn、Diagrams&#xff08;darw.io&#xff09;、XMind、Visio、yEd、Lucidcha…

2023年企业降低云支出的小方法汇总

据悉&#xff0c;2023年全球云基础设施服务支出全年将增长23%&#xff0c;也就是说云支出会持续增长。所以企业有效降低云支出是刻不容缓的。这里就给大家汇总了一些企业降低云支出的小方法&#xff0c;希望有用。 2023年企业降低云支出的小方法汇总 1、寻找价格折扣 提前计…

计算机图形学 | 实验十一:阴影计算

计算机图形学 | 实验十一&#xff1a;阴影计算 计算机图形学 | 实验十一&#xff1a;阴影计算帧缓冲创建一个帧缓冲纹理附件渲染缓冲对象附件总结 阴影映射算法思想深度贴图渲染阴影抗锯齿 assimp库结果 华中科技大学《计算机图形学》课程 MOOC地址&#xff1a;计算机图形学&a…

分布式ID解决方案(一)数据库号段方式

一、前言 在一些简单系统中&#xff0c;我们可以直接使用数据库ID自增方式来标识和保存数据&#xff0c;但是随着系统的逐渐复杂&#xff0c;数据量的日益增多&#xff0c;我们可能需要对数据表、数据库实现分库分表。单纯的使用数据库的ID自增无法满足业务场景了&#xff0c;所…

Seata 的可观测实践

作者&#xff1a;察溯 Seata 简介 Seata 的前身是阿里巴巴集团内大规模使用保证分布式事务一致性的中间件&#xff0c;Seata 是其开源产品&#xff0c;由社区维护。在介绍 Seata 前&#xff0c;先与大家讨论下我们业务发展过程中经常遇到的一些问题场景。 业务场景 我们业务…

数据规模缩小 200 倍!指令微调高效指导大模型学习

夕小瑶科技说 原创 作者 | 智商掉了一地、Python 最近大型语言模型&#xff08;LLMs&#xff09;的指令微调备受研究人员的关注&#xff0c;因为它可以开发 LLM 遵循指令的潜力&#xff0c;使其更加符合特定的任务需求。虽然指令微调&#xff08;Instruction Tuning&#xff…

JavaEE-HTTPS的加密流程

目录 对称加密非对称加密证书的引入 对称加密 对称加密就是用同一个密钥把明文进行加密变成密文,也能把密文解密为明文. 理想状态下: 引入对称加密之后, 即使数据被截获, 由于黑客不知道密钥是啥, 因此就无法进行解密, 也就不知道请求的真实内容是啥了. 但同一时刻服务器服务…

数据库规范与SQL调优

数据库设计规范章节&#xff0c;依旧以《阿里巴巴Java开发手册》为原型进行修正和完善。 MySQL规约 (一) 建表规约 (二) 索引规约 (三) SQL规约 (四) ORM规约 (一) 建表规约 1. 【强制】 表达是与否概念的字段&#xff0c;必须使用is_xxx的方式命名&#xff0c;数据类型是…

Windows修改为Mac的字体方法

一: 首先下载字体文件和修改器 Mac字体修改 https://www.aliyundrive.com/s/KKvcRNYkP5p 提取码: 6d3p 点击链接保存&#xff0c;或者复制本段内容&#xff0c;打开「阿里云盘」APP &#xff0c;无需下载极速在线查看&#xff0c;视频原画倍速播放。 二: 设置并修改字体 1:…

服务(第二十八篇)rsync

配置rsync源服务器&#xff1a; #建立/etc/rsyncd.conf 配置文件 vim /etc/rsyncd.conf #添加以下配置项 uid root gid root use chroot yes #禁锢在源目录 address 192.168.80.10 …