Android HandlerThread 基础
HandlerThread
- **一、HandlerThread的基本概念和用途**
- 1. **目的**
- 2. **与普通线程的区别**
- **二、HandlerThread的使用步骤**
- 1. **创建HandlerThread对象并启动线程**
- 2. **创建Handler并关联到HandlerThread的消息队列**
- 3. **发送消息到HandlerThread的消息队列**
- **三、HandlerThread的生命周期和注意事项**
- 1. **生命周期**
- 2. **注意事项**
- 四、使用 HandlerThread 和 线程池 举同一个例子
- 1. **使用HandlerThread的示例:下载文件并更新UI**
- 2. **使用线程池的示例:下载文件并更新UI(同样的功能)**
- 3.例子1中的 handler 不在主线程了么
- 参考地址
HandlerThread
是Android中的一个类,它继承自Thread
,主要用于在一个单独的线程中处理消息队列(MessageQueue
)。以下是关于它的详细内容:
一、HandlerThread的基本概念和用途
1. 目的
- 在Android开发中,为了避免在主线程(UI线程)执行耗时操作而导致应用程序出现“ANR(Application Not Responding)”的情况,需要将一些耗时任务(如网络请求、文件读写等)放到后台线程中执行。
HandlerThread
提供了一种方便的方式来创建一个带有消息队列的后台线程。(和handler一起配合使用达到)- 它允许通过
Handler
发送消息到该线程的消息队列中,然后在该线程中按照消息发送的顺序依次处理这些消息。这样就可以在一个单独的线程中有序地执行一系列任务。
2. 与普通线程的区别
-
普通线程没有自带的消息队列机制。如果要在普通线程中处理多个任务,需要自己实现任务调度和排队等复杂的逻辑。而
HandlerThread
内部已经实现了消息队列,并且可以通过Handler
方便地与其他线程进行通信。 -
例如,在一个普通线程中,如果要处理多个不同类型的任务,可能需要使用复杂的状态机或者阻塞队列等方式来管理任务。但是
HandlerThread
通过消息机制(Message
和MessageQueue
),可以很方便地通过sendMessage
等方法发送任务请求,并且在Handler
的handleMessage
方法中处理这些任务。
二、HandlerThread的使用步骤
1. 创建HandlerThread对象并启动线程
- 首先,需要创建一个
HandlerThread
对象。例如:
HandlerThread handlerThread = new HandlerThread("MyHandlerThread");
handlerThread.start();
- 这里创建了一个名为
MyHandlerThread
的HandlerThread
,然后调用start
方法来启动这个线程。启动后,该线程就会开始运行,并且创建一个与之关联的消息队列。
2. 创建Handler并关联到HandlerThread的消息队列
- 接着,需要创建一个
Handler
对象,并将其与HandlerThread
的消息队列关联起来。可以通过以下方式实现:
Handler handler = new Handler(handlerThread.getLooper()) {@Overridepublic void handleMessage(Message msg) {// 在这里处理消息switch (msg.what) {case 1:// 执行任务1break;case 2:// 执行任务2break;}}
};
- 这里通过
handlerThread.getLooper()
获取HandlerThread
的Looper
对象。Looper
是一个用于循环获取消息队列中的消息并分发给Handler
的类。通过这种方式,创建的Handler
就可以将消息发送到HandlerThread
的消息队列中,并且在handleMessage
方法中处理这些消息。
3. 发送消息到HandlerThread的消息队列
- 最后,可以通过
Handler
发送消息到HandlerThread
的消息队列中。例如:
Message message = new Message();
message.what = 1;
handler.sendMessage(message);
- 这里创建了一个
Message
对象,设置了消息的what
属性(用于区分不同类型的消息),然后通过handler.sendMessage
方法将消息发送到HandlerThread
的消息队列中。HandlerThread
中的Looper
会不断地从消息队列中获取消息,并将消息分发给关联的Handler
的handleMessage
方法进行处理。
三、HandlerThread的生命周期和注意事项
1. 生命周期
- 当
HandlerThread
对象被创建并调用start
方法后,线程开始运行,消息队列被创建,Looper
开始循环获取消息。 - 只要还有未处理的消息在消息队列中,或者
Looper
没有被显式地退出,HandlerThread
就会一直运行。可以通过调用HandlerThread
的quit
或者quitSafely
方法来退出Looper
,从而结束HandlerThread
的运行。例如:
handlerThread.quitSafely();
quitSafely
方法会在处理完当前消息队列中的已有消息后退出Looper
,而quit
方法会立即退出Looper
,可能会导致消息丢失。
2. 注意事项
- 内存泄漏:如果
Handler
对象是一个内部类,并且它间接引用了外部类(例如Activity)的实例,而HandlerThread
的生命周期又比外部类长,那么可能会导致外部类无法被垃圾回收,从而引起内存泄漏。为了避免这种情况,可以将Handler
定义为静态内部类,并使用弱引用(WeakReference
)来引用外部类实例。 - 消息处理顺序:
HandlerThread
中的消息是按照发送的顺序依次处理的。如果有高优先级的任务,需要在消息机制的基础上进行适当的调整,例如可以通过设置消息的优先级或者在handleMessage
方法中根据任务的紧急程度优先处理某些消息。
四、使用 HandlerThread 和 线程池 举同一个例子
1. 使用HandlerThread的示例:下载文件并更新UI
- 布局文件(activity_main.xml)
- 简单的布局包含一个按钮用于触发下载和一个文本视图用于显示下载状态。
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:orientation="vertical"android:layout_width="match_parent"android:layout_height="match_parent"><Buttonandroid:id="@+id/download_button"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="下载文件"/><TextViewandroid:id="@+id/status_text"android:layout_width="wrap_content"android:layout_height="wrap_content"/> </LinearLayout>
- Java代码(MainActivity.java)
- 在
MainActivity
中实现下载文件的功能。
import android.os.Bundle; import android.os.Handler; import android.os.HandlerThread; import android.os.Message; import android.view.View; import android.widget.Button; import android.widget.TextView; import androidx.appcompat.app.AppCompatActivity; public class MainActivity extends AppCompatActivity {private HandlerThread handlerThread;private Handler handler;private TextView statusText;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);Button downloadButton = findViewById(R.id.download_button);statusText = findViewById(R.id.status_text);// 创建HandlerThread并启动handlerThread = new HandlerThread("DownloadThread");handlerThread.start();// 创建Handler并关联到HandlerThread的消息队列handler = new Handler(handlerThread.getLooper()) {@Overridepublic void handleMessage(Message msg) {if (msg.what == 1) {// 模拟下载文件的过程try {Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}// 下载完成后发送消息到主线程更新UIMessage uiMessage = new Message();uiMessage.what = 2;uiHandler.sendMessage(uiMessage);}}};downloadButton.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {// 发送下载文件的消息到HandlerThreadMessage downloadMessage = new Message();downloadMessage.what = 1;handler.sendMessage(downloadMessage);statusText.setText("正在下载...");}});// 创建用于更新UI的主线程HandlerHandler uiHandler = new Handler(getMainLooper()) {@Overridepublic void handleMessage(Message msg) {if (msg.what == 2) {statusText.setText("下载完成");}}};}@Overrideprotected void onDestroy() {super.onDestroy();// 退出HandlerThreadhandlerThread.quitSafely();} }
- 首先,在
onCreate
方法中创建HandlerThread
并启动它,然后创建与HandlerThread
消息队列关联的Handler
。当用户点击下载按钮时,发送一个消息到HandlerThread
的消息队列,在handleMessage
方法中模拟文件下载过程(这里通过Thread.sleep
来模拟耗时操作)。下载完成后,发送一个消息到主线程的Handler
来更新UI,显示下载完成的状态。最后,在onDestroy
方法中退出HandlerThread
。
- 在
2. 使用线程池的示例:下载文件并更新UI(同样的功能)
- 布局文件(与上面相同,activity_main.xml)
- Java代码(MainActivity.java)
import android.os.Bundle; import android.os.Handler; import android.view.View; import android.widget.Button; import android.widget.TextView; import androidx.appcompat.app.AppCompatActivity; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class MainActivity extends AppCompatActivity {private ExecutorService executorService;private TextView statusText;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);Button downloadButton = findViewById(R.id.download_button);statusText = findViewById(R.id.status_text);// 创建一个单线程的线程池(这里可以根据需要调整线程池大小)executorService = Executors.newSingleThreadExecutor();downloadButton.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {statusText.setText("正在下载...");// 提交下载任务到线程池executorService.submit(new Runnable() {@Overridepublic void run() {try {// 模拟下载文件的过程Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}// 下载完成后发送消息到主线程更新UIHandler uiHandler = new Handler(getMainLooper()) {@Overridepublic void handleMessage(Message msg) {if (msg.what == 1) {statusText.setText("下载完成");}}};Message uiMessage = new Message();uiMessage.what = 1;uiHandler.sendMessage(uiMessage);}});}});}@Overrideprotected void onDestroy() {super.onDestroy();// 关闭线程池executorService.shutdown();} }
- 这里在
onCreate
方法中创建一个单线程的线程池ExecutorService
。当用户点击下载按钮时,将下载任务以Runnable
的形式提交到线程池。在Runnable
的run
方法中模拟文件下载过程,下载完成后,创建一个主线程的Handler
,并发送消息到主线程来更新UI,显示下载完成的状态。最后,在onDestroy
方法中关闭线程池。这两种方式都实现了在后台执行下载任务,避免阻塞主线程,并且在任务完成后更新UI的功能。
- 这里在
3.例子1中的 handler 不在主线程了么
handler
不在主线程中- 在第一个例子中,
handler
关联的是HandlerThread
的Looper
,而HandlerThread
是一个单独的后台线程。当创建handler
时,通过handlerThread.getLooper()
获取的是HandlerThread
线程中的Looper
对象。 - 例如,代码中的这部分:
handler = new Handler(handlerThread.getLooper()) {@Overridepublic void handleMessage(Message msg) {if (msg.what == 1) {// 模拟下载文件的过程try {Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}// 下载完成后发送消息到主线程更新UIMessage uiMessage = new Message();uiMessage.what = 2;uiHandler.sendMessage(uiMessage);}} };
- 这个
handler
的handleMessage
方法是在HandlerThread
线程中执行的。HandlerThread
提供了一个后台线程环境,这样就可以在这个线程中执行一些耗时的操作,比如模拟文件下载(通过Thread.sleep
来模拟耗时),而不会阻塞主线程。
- 在第一个例子中,
- 与主线程通信的
uiHandler
- 为了更新UI,又创建了一个
uiHandler
,它是关联到主线程(UI线程)的Looper
的。 - 代码如下:
Handler uiHandler = new Handler(getMainLooper()) {@Overridepublic void handleMessage(Message msg) {if (msg.what == 2) {statusText.setText("下载完成");}} };
- 当后台
HandlerThread
中的任务完成后,通过uiHandler
发送消息到主线程的消息队列,然后在主线程中执行uiHandler
的handleMessage
方法来更新UI。这是因为在Android中,只有主线程才能更新UI,所以需要这种跨线程通信的方式来在后台任务完成后更新界面显示。
- 为了更新UI,又创建了一个
参考地址
豆包 AI
相关文章:
Android HandlerThread 基础
HandlerThread **一、HandlerThread的基本概念和用途**1. **目的**2. **与普通线程的区别** **二、HandlerThread的使用步骤**1. **创建HandlerThread对象并启动线程**2. **创建Handler并关联到HandlerThread的消息队列**3. **发送消息到HandlerThread的消息队列** **三、Handl…...
【智能算法应用】人工水母搜索算法求解二维路径规划问题
摘要 本文基于人工水母搜索算法(Jellyfish Search Algorithm, JSA),对二维路径规划问题进行了研究。JSA作为一种新兴的群体智能优化算法,模仿了水母在海洋中觅食和迁移的行为,以求解非线性、复杂的优化问题。实验结果…...
【Altium】原理图如何利用参数管理器批量修改元器件属性
【更多软件使用问题请点击亿道电子官方网站】 1、 文档目标 解决在使用AD设计原理图的时候,使用参数管理器批量修改元器件的属性。 2、 问题场景 客户在使用ad时,想大批量修改元器件的属性,类似于Cadence中,批量修改Manufactur…...
基于Spring Boot与Redis的令牌主动失效机制实现
目录 前言1. 项目结构和依赖配置1.1 项目依赖配置1.2 Redis连接配置 2. 令牌主动失效机制的实现流程2.1 登录成功后将令牌存储到Redis中2.2 使用拦截器验证令牌2.3 用户修改密码后删除旧令牌 3. Redis的配置与测试4. 可能的扩展与优化结语 前言 在现代Web系统中,用…...
深度学习之循环神经网络(RNN)
1 为什么需要RNN? 时间序列数据是指在不同时间点上收集到的数据,这类数据反映了某一事物、现象等随时间的变化状态或程度。一般的神经网络,在训练数据足够、算法模型优越的情况下,给定特定的x,就能得到期望y。其一…...
Autosar CP Network Management模块规范导读
Network Management模块的主要功能 网络管理适配:作为通信管理器和总线特定网络管理模块之间的适配层,实现不同总线网络管理功能的统一接口,确保系统中各种网络的协同工作。协调功能 网络协调关闭:使用协调算法协调多个网络的关闭,确保它们在合适的时间同步进入睡眠模式,…...
Xshell 7 偏好设置
1 Xshell7 工具——更改用户数据文件夹 就是此电脑目录下的文档 该目录下的7 Xshell下的 applog ColorScheme Files 配色方案文件目录 HighlightSet Files 突出显示集目录 Logs 日志 QuickButton Files 快速命令集 Scripts 脚本文件 Sessions 会话文件 会话文件目录就…...
云计算答案
情境一习题练习 一、选择题 1、在虚拟机VMware软件中实现联网过程,图中箭头所指的网络连接方式与下列哪个相关( C )。 A.仅主机模式 B.桥接 C.NAT D.嫁接 2、请问下图这个虚拟化架构属于什么类型( A …...
浅谈现货白银与白银td的价格差异
西方资本主义世界崇尚自由经济,而我国实行社会主义市场经济,因此二者在金融系统上存在不少差异,反映在贵金属市场中,可能直接表现为价格上的差异。如果投资者对此能有基本的了解,日后面对交易中的特殊价格波动…...
【QT常用技术讲解】任务栏图标+socket网络服务+开机自启动
前言 首先看网络编程的定义:两个不同主机设备之间的进程通信。C/S(Client-Server)是早期非常典型的软件架构,C/S架构虽然简单,但却非常适用于桌面图形化的QT项目。 本篇的QT项目是从真实的项目中简化出来,满足很多相似的场景&…...
【计算机基础——数据结构——AVL平衡二叉树】
1. BST二叉查找树 1.1 BST二叉查找树的特性 左子树上所有结点的值均小于或等于它的根结点的值。右子树上所有结点的值均大于或等于它的根结点的值。左、右子树也分别为二叉排序树。 1.2 BST二叉查找树的缺点 二叉查找树是有缺点的,在不断插入的时候,…...
体育活动赛事报名马拉松微信小程序开发
功能描述 体育活动赛事报名马拉松微信小程序,该项目是一个体育活动报名小程序,主要功能有活动报名、扫码签到、签到积分、排行奖励、积分兑换等功能。 用户端🔶登录:◻️1.微信授权登录 ◻️2.手机号码授权 🔶首页&am…...
【C++】C++基础知识
一.函数重载 1.函数重载的概念 函数重载是函数的一种特殊情况,C允许在同一作用域中声明几个功能类似的同名函数,这些同名函数的形参列表必须不同。函数重载常用来处理实现功能类似,而数据类型不同的问题。 #include <iostream> using…...
中间件安全
IIS IIS短文件漏洞 此漏洞实际是由HTTP请求中旧DOS 8.3名称约定(SFN)的代字符(~)波浪号引起的。它允许远程攻击者在Web根目录下公开文件和文件夹名称(不应该可被访问)。攻击者可以找到通常无法从外部直接访问的重要文件,并获取有关应用程序基础结构的信息。 利用工具 https…...
Zabbix中文监控指标数据乱码
1)点击主机,选择Zabbix server 中的 图形 一项,可以看到当前显示的为乱码 2) 下载字体文件: https://gitcode.com/open-source-toolkit/4a3db/blob/main/SimHei.zip 解压unzip -x SimHei.zip 3) 替换字体文…...
【AI】AI如何赋能软件开发流程
方向一:流程与模式介绍【传统软件开发 VS AI参与的软件开发】 传统软件开发流程 传统软件开发流程一般可以分为以下几个阶段: 1. 需求分析:在这个阶段,开发团队与客户沟通,明确软件的需求和目标。团队会收集、整理和分…...
恒创科技:什么是 RAID 3 ? RAID 3、4 和5之间有什么区别?
RAID 是一种存储数据以提高性能并减少数据丢失的特定技术。您可以根据自己的需求选择多种 RAID 类型。RAID 3 是列表中比较有效的类型之一。本文将重点介绍这种特定的 RAID 技术,并比较 RAID 3、4 和 5。 RAID 3 的定义 RAID 3 是一种特定的磁盘配置,用于…...
python获取iOS最近业务日志的两种方法
当iOS UI自动化用例执行失败的时候,需要获取当时的业务日志,供后续分析使用。 现在已经把iOS沙盒目录挂载到本地,剩下的事情就是从沙盒目录中捞取当前的日志,沙盒中的日志文件较大,整体导出来也可以,但是会…...
【如何获取股票数据43】Python、Java等多种主流语言实例演示获取股票行情api接口之沪深指数历史交易数据获取实例演示及接口API说明文档
最近一两年内,股票量化分析逐渐成为热门话题。而从事这一领域工作的第一步,就是获取全面且准确的股票数据。因为无论是实时交易数据、历史交易记录、财务数据还是基本面信息,这些数据都是我们进行量化分析时不可或缺的宝贵资源。我们的主要任…...
ESLint 使用教程(一):从零配置 ESLint
前言 在现代前端开发中,代码质量和风格一致性是团队合作和项目维护的重要因素。而 ESLint 作为一款强大的 JavaScript 静态代码分析工具,能够帮助开发者发现和修复代码中的潜在问题。本文将详细介绍 ESLint 的常用规则配置,并结合实际应用场…...
openssl对称加密代码讲解实战
文章目录 一、openssl对称加密和非对称加密算法对比1. 加密原理2. 常用算法3. 加密速度4. 安全性5. 应用场景6. 优缺点对比综合分析 二、代码实战代码说明:运行输出示例代码说明:注意事项 一、openssl对称加密和非对称加密算法对比 OpenSSL 是一个广泛使…...
web前端动画按钮(附源代码)
效果图 源代码 HTML部分 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title> …...
go函数传值是值传递?还是引用传递?slice案例加图解
先说下结论 Go语言中所有的传参都是值传递(传值),都是一个副本,一个拷贝。 值语义类型:参数传递的时候,就是值拷贝,这样就在函数中就无法修改原内容数据。 基本类型:byte、int、bool…...
PostgreSQL数据库笔记
PostgreSQL 是什么 PostgreSQL(简称Postgres或PG)是一个功能强大、可靠性高、可扩展性好的开源对象-关系数据库服务器(ORDBMS),它以加州大学伯克利分校计算机系开发的POSTGRES版本4.2为基础。 发展历程 起源与发展&a…...
财务软件源码SaaS云财务
在如今的商业环境中,准确的财务管理是一家企业取得成功的关键。然而,传统的财务管理方法已经无法满足现代企业的需求,需要一个全新的解决方案。推出了全新的财务软件为您提供完美的解决方案。 选择财务软件源码,您将享受到以下优…...
Elasticsearch集群和Kibana部署流程
搭建Elasticsearch集群 1. 进入Elasticsearch官网下载页面,下载Elasticsearch 在如下页面选择Elasticsearch版本,点击download按钮,进入下载页面 右键选择自己操作系统对应的版本,复制下载链接 然后通过wget命令下载Elastics…...
丹摩征文活动 | 丹摩智算:大数据治理的智慧引擎与实践探索
丹摩DAMODEL|让AI开发更简单!算力租赁上丹摩! 目录 一、引言 二、大数据治理的挑战与重要性 (一)数据质量问题 (二)数据安全威胁 (三)数据管理复杂性 三、丹摩智算…...
【Django】Clickjacking点击劫持攻击实现和防御措施
Clickjacking点击劫持 1、clickjacking攻击2、clickjacking攻击场景 1、clickjacking攻击 clickjacking攻击又称为点击劫持攻击,是一种在网页中将恶意代码等隐藏在看似无害的内容(如按钮)之下,并诱使用户点击的手段。 2、clickj…...
Ansys Zemax | 手机镜头设计 - 第 4 部分:用LS-DYNA进行冲击性能分析
该系列文章将讨论智能手机镜头模组设计的挑战,从概念和设计到制造和结构变形分析。本文是四部分系列中的第四部分,它涵盖了相机镜头的显式动态模拟,以及对光学性能的影响。使用Ansys Mechanical和LS-DYNA对相机在地板上的一系列冲击和弹跳过程…...
工具收集 - java-decompiler / jd-gui
工具收集 - java-decompiler / jd-gui 参考资料 用法:拖进来就行了 参考资料 https://github.com/java-decompiler/jd-gui 脚本之家:java反编译工具jd-gui使用详解...
中国企业500强全部名单/seo优化设计
memcache课程---3、php使用memcache缓存实例 一、总结 一句话总结: 前置:windows下安装好memcache.exe,安装好memcache的php扩展,开启memcache服务,连接memcache服务 函数:去php的手册里面找memcache 核心伪…...
php做购物网站/goole官网
四、PL/SQL命名规范 同样的命名规约适用于所有的PL/SQL程序,规约涉及的内容包括常量、变量、游标、异常、过程、函数和包。命名可能是简单的,加以限定的,远程的或是既加以限定又是远程的。例如,我们也许可能用到以下几种调用过程r…...
17网站一起做网店潮汕档口/cba赛程
在计算机科学中,B树(英语:B-tree)是一种自平衡的树,能够保持数据有序。这种数据结构能够让查找数据、顺序访问、插入数据及删除的动作,都在对数时间内完成。B树,概括来说是一个一般化的二叉查找…...
web前端开发自学网/seo网络营销是什么意思
译者:Hawstein原文:google.github.io/styleguide/javaguide.html来源:hawstein.com/2014/01/20/google-java-style/这份文档是Google Java编程风格规范的完整定义。当且仅当一个Java源文件符合此文档中的规则, 我们才认为它符合Go…...
无锡哪里做网站/中国域名网官网
之前有一个工作是到服务器上去复制一串文字下来,很简单的操作,但是需要重复50次左右,每次花费大概三分钟,一遍下来两个多小时就进去了。因此就做了这个工具自动抓取数据。 工具主要做三件事情:登陆,下载&am…...
网站开发与优化课程总结/文明seo技术教程网
寻路组件是一种可在虚幻引擎 4 中修改或扩展 NavMesh(Pathfinding) 系统功能的组件。 Nav Modifier Component (导航修改器组件) Nav Modifier Component 本身没有任何功能,但是,如果您有一个基本形状组件作为 Actor 的根…...