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

相关文章

Android Kotlin 高阶函数详解及其在协程中的应用小结

《AndroidKotlin高阶函数详解及其在协程中的应用小结》高阶函数是Kotlin中的一个重要特性,它能够将函数作为一等公民(First-ClassCitizen),使得代码更加简洁、灵活和可... 目录1. 引言2. 什么是高阶函数?3. 高阶函数的基础用法3.1 传递函数作为参数3.2 Lambda

Android自定义Scrollbar的两种实现方式

《Android自定义Scrollbar的两种实现方式》本文介绍两种实现自定义滚动条的方法,分别通过ItemDecoration方案和独立View方案实现滚动条定制化,文章通过代码示例讲解的非常详细,... 目录方案一:ItemDecoration实现(推荐用于RecyclerView)实现原理完整代码实现

Java使用多线程处理未知任务数的方案介绍

《Java使用多线程处理未知任务数的方案介绍》这篇文章主要为大家详细介绍了Java如何使用多线程实现处理未知任务数,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 知道任务个数,你可以定义好线程数规则,生成线程数去跑代码说明:1.虚拟线程池:使用 Executors.newVir

Android App安装列表获取方法(实践方案)

《AndroidApp安装列表获取方法(实践方案)》文章介绍了Android11及以上版本获取应用列表的方案调整,包括权限配置、白名单配置和action配置三种方式,并提供了相应的Java和Kotl... 目录前言实现方案         方案概述一、 androidManifest 三种配置方式

JAVA封装多线程实现的方式及原理

《JAVA封装多线程实现的方式及原理》:本文主要介绍Java中封装多线程的原理和常见方式,通过封装可以简化多线程的使用,提高安全性,并增强代码的可维护性和可扩展性,需要的朋友可以参考下... 目录前言一、封装的目标二、常见的封装方式及原理总结前言在 Java 中,封装多线程的原理主要围绕着将多线程相关的操

Android WebView无法加载H5页面的常见问题和解决方法

《AndroidWebView无法加载H5页面的常见问题和解决方法》AndroidWebView是一种视图组件,使得Android应用能够显示网页内容,它基于Chromium,具备现代浏览器的许多功... 目录1. WebView 简介2. 常见问题3. 网络权限设置4. 启用 JavaScript5. D

Android如何获取当前CPU频率和占用率

《Android如何获取当前CPU频率和占用率》最近在优化App的性能,需要获取当前CPU视频频率和占用率,所以本文小编就来和大家总结一下如何在Android中获取当前CPU频率和占用率吧... 最近在优化 App 的性能,需要获取当前 CPU视频频率和占用率,通过查询资料,大致思路如下:目前没有标准的

Android开发中gradle下载缓慢的问题级解决方法

《Android开发中gradle下载缓慢的问题级解决方法》本文介绍了解决Android开发中Gradle下载缓慢问题的几种方法,本文给大家介绍的非常详细,感兴趣的朋友跟随小编一起看看吧... 目录一、网络环境优化二、Gradle版本与配置优化三、其他优化措施针对android开发中Gradle下载缓慢的问

Python中多线程和多进程的基本用法详解

《Python中多线程和多进程的基本用法详解》这篇文章介绍了Python中多线程和多进程的相关知识,包括并发编程的优势,多线程和多进程的概念、适用场景、示例代码,线程池和进程池的使用,以及如何选择合适... 目录引言一、并发编程的主要优势二、python的多线程(Threading)1. 什么是多线程?2.

Android 悬浮窗开发示例((动态权限请求 | 前台服务和通知 | 悬浮窗创建 )

《Android悬浮窗开发示例((动态权限请求|前台服务和通知|悬浮窗创建)》本文介绍了Android悬浮窗的实现效果,包括动态权限请求、前台服务和通知的使用,悬浮窗权限需要动态申请并引导... 目录一、悬浮窗 动态权限请求1、动态请求权限2、悬浮窗权限说明3、检查动态权限4、申请动态权限5、权限设置完毕后