Android之Handler与多线程

2024-08-30 01:38
文章标签 android 多线程 handler

本文主要是介绍Android之Handler与多线程,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

声明: 本人菜鸟一枚, 本博客是本人自学的内容, 适用于初学者, 不喜勿喷, 谢谢大家

  • Handler介绍
  • Handler常用API
  • Handle内部实现原理
  • Handler内存泄漏问题分析


Handler介绍

对于像我这样的菜鸟来说, 刚开始学Android的时候, 如果想要实现类似下载的功能, 可能会这样写:

    public void downloadClick(View view) {new Thread(new Runnable() {@Overridepublic void run() {//模拟下载try {Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}//下载完成后的操作textView.setText("下载完成");}}).start();}

这样写带来的后果是: 崩了

错误日志

android.view.ViewRootImpl$CalledFromWrongThreadException: 
Only the original thread that created a view

对于熟悉Android开发的人看来是非常可笑的事情, 因为在多线程操作时我们忽略了两点:

  1. 不允许阻塞UI线程(主线程)
  2. 不能在UI线程之外访问Android UI工具包

以上是Android开发不可逾越的红线, 必须遵守.

但是我们还需要在子线程和主线程之间传递数据, 该怎么办呢? 那就得用我们的Handler

Handler常用API

Handler可以完成下述两点工作:

  1. 消息调度和将来的某个时间点执行一个Runnable
  2. 多个任务加入到一个队列中

对于刚才的代码我们可以这样改

private Handler handler = new Handler(){@Overridepublic void handleMessage(Message msg) {super.handleMessage(msg);switch (msg.what){case 1:textView.setText("下载成功");break;}}};public void downloadClick(View view) {new Thread(new Runnable() {@Overridepublic void run() {//模拟下载try {Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}handler.sendEmptyMessage(1);}}).start();}

列举一下常用的API

handler.sendEmptyMessage(1);//发送空消息,
Message msg = handler.obtainMessage();  //从全局的消息池中返回一个Message对象
msg.what = 2;//设置标记
handler.sendMessage(msg);
handler.sendEmptyMessageAtTime(3, System.currentTimeMillis() + 3000);//表示在3s后发送一个空消息
handler.sendEmptyMessageDelayed(4, 3000); //含义同时, 延迟发送消息
//其他的都大同小异, 就不一一列举了

Handle内部实现原理

Handler实现机制:
1. Message对象, 表示要传递的一个消息, 内部使用数据结构实现消息池, 用于重复利用, 避免大量创建消息对象, 造成内存浪费
2. MessageQueue对象, 存放消息对象的消息队列, 先进先出原则
3. Looper对象负责管理当前线程的消息队列(MessageQueue), 用于循环检查消息队列, 从消息队列中一个一个的取出消息对象, 传入handlerMessage() 方法中
4. Handler对象负责把消息push到消息队列中, 以及接收并处理Looper从消息队列中取出的消息
图示说明:
这里写图片描述

Android启动程序时会在UI线程创建一个MessageQueue

Handler内存泄漏问题分析

如果我们仔细看我们之前写得程序在创建handler处有个黄色的叹号, 将详细信息调出来会是下面的样子

这里写图片描述

这就引出了我们所说的Handler的内存泄漏问题

到底哪儿出了问题呢??
大家仔细想想我们学习Java的时候, 在讲内部类的时候会讲到, 当我们创建一个内部类对象时, 我们的内部类对象默认会依附于外部类对象的存在而存在. 所以大家试想下面的例子:

handler.postDelayed(new Runnable() {@Overridepublic void run() {System.out.println("Test");}
}, 1000*60*5);
finish();

在这种情况下,当执行完了postDelayed方法之后当前的Activity会立即finsh(), 但是大家要想到此时我们的handler是依附于外部类的 , 所以此时的Activity并没有真正的关掉

问题的解决
1. 定义一个内部类时会默认拥有外部类对象的引用, 所以最好我们定义一个静态的内部类
2. 使用弱引用, 即使用 引用的强弱分为: 强引用 => 软引用 => 弱引用 ,如果实在不清楚之间的关系请直接百度一下

    private MyHandler myHandler= new MyHandler(this);private static class MyHandler extends Handler{WeakReference<HandlerMemoryActivity> weakReference;public MyHandler(HandlerMemoryActivity activity) {weakReference = new WeakReference<HandlerMemoryActivity>(activity);}@Overridepublic void handleMessage(Message msg) {super.handleMessage(msg);HandlerMemoryActivity activity = weakReference.get();if (activity != null){//这里写对Activity的操作}}}

座右铭: 少说话, 多做事

这篇关于Android之Handler与多线程的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1119436

相关文章

SpringBoot分段处理List集合多线程批量插入数据方式

《SpringBoot分段处理List集合多线程批量插入数据方式》文章介绍如何处理大数据量List批量插入数据库的优化方案:通过拆分List并分配独立线程处理,结合Spring线程池与异步方法提升效率... 目录项目场景解决方案1.实体类2.Mapper3.spring容器注入线程池bejsan对象4.创建

Android协程高级用法大全

《Android协程高级用法大全》这篇文章给大家介绍Android协程高级用法大全,本文结合实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友跟随小编一起学习吧... 目录1️⃣ 协程作用域(CoroutineScope)与生命周期绑定Activity/Fragment 中手

Python多线程实现大文件快速下载的代码实现

《Python多线程实现大文件快速下载的代码实现》在互联网时代,文件下载是日常操作之一,尤其是大文件,然而,网络条件不稳定或带宽有限时,下载速度会变得很慢,本文将介绍如何使用Python实现多线程下载... 目录引言一、多线程下载原理二、python实现多线程下载代码说明:三、实战案例四、注意事项五、总结引

Python多线程应用中的卡死问题优化方案指南

《Python多线程应用中的卡死问题优化方案指南》在利用Python语言开发某查询软件时,遇到了点击搜索按钮后软件卡死的问题,本文将简单分析一下出现的原因以及对应的优化方案,希望对大家有所帮助... 目录问题描述优化方案1. 网络请求优化2. 多线程架构优化3. 全局异常处理4. 配置管理优化优化效果1.

Android 缓存日志Logcat导出与分析最佳实践

《Android缓存日志Logcat导出与分析最佳实践》本文全面介绍AndroidLogcat缓存日志的导出与分析方法,涵盖按进程、缓冲区类型及日志级别过滤,自动化工具使用,常见问题解决方案和最佳实... 目录android 缓存日志(Logcat)导出与分析全攻略为什么要导出缓存日志?按需过滤导出1. 按

Qt中实现多线程导出数据功能的四种方式小结

《Qt中实现多线程导出数据功能的四种方式小结》在以往的项目开发中,在很多地方用到了多线程,本文将记录下在Qt开发中用到的多线程技术实现方法,以导出指定范围的数字到txt文件为例,展示多线程不同的实现方... 目录前言导出文件的示例工具类QThreadQObject的moveToThread方法实现多线程QC

Android Paging 分页加载库使用实践

《AndroidPaging分页加载库使用实践》AndroidPaging库是Jetpack组件的一部分,它提供了一套完整的解决方案来处理大型数据集的分页加载,本文将深入探讨Paging库... 目录前言一、Paging 库概述二、Paging 3 核心组件1. PagingSource2. Pager3.

RabbitMQ消费端单线程与多线程案例讲解

《RabbitMQ消费端单线程与多线程案例讲解》文章解析RabbitMQ消费端单线程与多线程处理机制,说明concurrency控制消费者数量,max-concurrency控制最大线程数,prefe... 目录 一、基础概念详细解释:举个例子:✅ 单消费者 + 单线程消费❌ 单消费者 + 多线程消费❌ 多

Android kotlin中 Channel 和 Flow 的区别和选择使用场景分析

《Androidkotlin中Channel和Flow的区别和选择使用场景分析》Kotlin协程中,Flow是冷数据流,按需触发,适合响应式数据处理;Channel是热数据流,持续发送,支持... 目录一、基本概念界定FlowChannel二、核心特性对比数据生产触发条件生产与消费的关系背压处理机制生命周期

Android ClassLoader加载机制详解

《AndroidClassLoader加载机制详解》Android的ClassLoader负责加载.dex文件,基于双亲委派模型,支持热修复和插件化,需注意类冲突、内存泄漏和兼容性问题,本文给大家介... 目录一、ClassLoader概述1.1 类加载的基本概念1.2 android与Java Class