Android多线程:HandlerThread详细使用手册

前言

  • 多线程的应用在Android开发中是非常常见的,常用方法主要有:

    1. 继承Thread类
    2. 实现Runnable接口
    3. Handler
    4. AsyncTask
    5. HandlerThread
  • 今天,我将全面解析多线程其中一种常见用法:HandlerThread

由于本文涉及多线程知识和Handler源码解析,所以阅读本文前建议先看: 
Android开发:Handler异步通信机制全面解析(包含Looper、Message Queue)


目录


1. 定义

一个Android 已封装好的轻量级异步类


2. 作用

  1. 实现多线程 
    在工作线程中执行任务,如 耗时任务
  2. 异步通信、消息传递 
    实现工作线程 & 主线程(UI线程)之间的通信,即:将工作线程的执行结果传递给主线程,从而在主线程中执行相关的UI操作

    从而保证线程安全


3. 优点

方便实现异步通信,即不需使用 “任务线程(如继承Thread类) + Handler”的复杂组合

实际上,HandlerThread本质上是通过继承Thread类和封装Handler类的使用,从而使得创建新线程和与其他线程进行通信变得更加方便易用


4. 工作原理

内部原理 = Thread类 + Handler类机制,即:

  • 通过继承Thread类,快速地创建1个带有Looper对象的新工作线程
  • 通过封装Handler类,快速创建Handler & 与其他线程进行通信

5. 使用步骤

  • HandlerThread的本质:继承Thread类 & 封装Handler
  • HandlerThread的使用步骤分为5步
// 步骤1:创建HandlerThread实例对象
// 传入参数 = 线程名字,作用 = 标记该线程HandlerThread mHandlerThread = new HandlerThread("handlerThread");// 步骤2:启动线程mHandlerThread.start();// 步骤3:创建工作线程Handler & 复写handleMessage()
// 作用:关联HandlerThread的Looper对象、实现消息处理操作 & 与其他线程进行通信
// 注:消息处理操作(HandlerMessage())的执行线程 = mHandlerThread所创建的工作线程中执行Handler workHandler = new Handler( handlerThread.getLooper() ) {@Overridepublic boolean handleMessage(Message msg) {...//消息处理return true;}});// 步骤4:使用工作线程Handler向工作线程的消息队列发送消息
// 在工作线程中,当消息循环时取出对应消息 & 在工作线程执行相关操作// a. 定义要发送的消息Message msg = Message.obtain();msg.what = 2; //消息的标识msg.obj = "B"; // 消息的存放// b. 通过Handler发送消息到其绑定的消息队列workHandler.sendMessage(msg);// 步骤5:结束线程,即停止线程的消息循环mHandlerThread.quit();

6. 实例讲解

下面,我将用一个实例讲解`HandlerThread`该如何使用

6.1 实例说明

  1. 点击按钮实现延迟操作
  2. 最终更新UI组件

6.2 具体实现

建议先下载源码再阅读:Carson_Ho的Github:HandlerThread

  • 主布局文件:activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:gravity="center"tools:context="com.example.carson_ho.handler_learning.MainActivity"><TextView
        android:id="@+id/text1"android:layout_centerInParent="true"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="测试结果" /><Button
        android:id="@+id/button1"android:layout_centerInParent="true"android:layout_below="@+id/text1"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="点击延迟1s + 显示我爱学习"/><Button
        android:id="@+id/button2"android:layout_centerInParent="true"android:layout_below="@+id/button1"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="点击延迟3s + 显示我不爱学习"/><Button
        android:id="@+id/button3"android:layout_centerInParent="true"android:layout_below="@+id/button2"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="结束线程的消息循环"/>
</RelativeLayout>
  • 主代码文件:MainActivity.java
public class MainActivity extends AppCompatActivity {Handler mainHandler,workHandler;HandlerThread mHandlerThread;TextView text;Button button1,button2,button3;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);// 显示文本text = (TextView) findViewById(R.id.text1);// 创建与主线程关联的HandlermainHandler = new Handler();/*** 步骤1:创建HandlerThread实例对象* 传入参数 = 线程名字,作用 = 标记该线程*/mHandlerThread = new HandlerThread("handlerThread");/*** 步骤2:启动线程*/mHandlerThread.start();/*** 步骤3:创建工作线程Handler & 复写handleMessage()* 作用:关联HandlerThread的Looper对象、实现消息处理操作 & 与其他线程进行通信* 注:消息处理操作(HandlerMessage())的执行线程 = mHandlerThread所创建的工作线程中执行*/workHandler = new Handler(mHandlerThread.getLooper()){@Override// 消息处理的操作public void handleMessage(Message msg){//设置了两种消息处理操作,通过msg来进行识别switch(msg.what){// 消息1case 1:try {//延时操作Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}// 通过主线程Handler.post方法进行在主线程的UI更新操作mainHandler.post(new Runnable() {@Overridepublic void run () {text.setText("我爱学习");}});break;// 消息2case 2:try {Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}mainHandler.post(new Runnable() {@Overridepublic void run () {text.setText("我不喜欢学习");}});break;default:break;}}};/*** 步骤4:使用工作线程Handler向工作线程的消息队列发送消息* 在工作线程中,当消息循环时取出对应消息 & 在工作线程执行相关操作*/// 点击Button1button1 = (Button) findViewById(R.id.button1);button1.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {// 通过sendMessage()发送// a. 定义要发送的消息Message msg = Message.obtain();msg.what = 1; //消息的标识msg.obj = "A"; // 消息的存放// b. 通过Handler发送消息到其绑定的消息队列workHandler.sendMessage(msg);}});// 点击Button2button2 = (Button) findViewById(R.id.button2);button2.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {// 通过sendMessage()发送// a. 定义要发送的消息Message msg = Message.obtain();msg.what = 2; //消息的标识msg.obj = "B"; // 消息的存放// b. 通过Handler发送消息到其绑定的消息队列workHandler.sendMessage(msg);}});// 点击Button3// 作用:退出消息循环button3 = (Button) findViewById(R.id.button3);button3.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {mHandlerThread.quit();}});}}
  • 运行结果

  • 源码地址 
    Carson_Ho的Github:HandlerThread

6.3 特别注意点

细节问题1:内存泄露

  • 在上面的例子中,出现了严重的警告:
In Android, Handler classes should be static or leaks might occur.
  • 1
  • 即造成了严重的内存泄漏,关于Handler的内存泄露请看文章:Android 内存泄露:详解 Handler 内存泄露的原因

细节问题2:连续发送消息

  • 当你连续点击3下时,发现并无按照最新点击的按钮操作显示,而是按顺序的一个个显示出来
  • 原因:使用HandlerThread时只是开了一个工作线程,当你点击了n下后,只是将n个消息发送到消息队列MessageQueue里排队,等候派发消息给Handler再进行对应的操作

7. 源码分析

  • 知其然 而须知其所以然,了解 HandlerThread 的源码分析有利于更好地理解HandlerThread的工作原理
  • 具体请看文章:Android多线程:这是一份详细的HandlerThread源码分析攻略 

8. 总结

  • 本文全面介绍了多线程 HandlerThread的用法 & 源码
  • 接下来,我会继续讲解Android开发中关于多线程的知识,包括继承Thread类、实现Runnable接口、Handler等等,有兴趣

Android 系统(152)---Android多线程:HandlerThread详细使用手册相关推荐

  1. android log抓取方法,Android系统之Android抓取各种log的方法

    Android系统之Android抓取各种log的方法 2018年11月25日 | 萬仟网移动技术 | 我要评论 android之android抓取各种log的方法 1.logcat (四类log b ...

  2. Android系统架构-[Android取经之路]

    摘要:本节主要来讲解Android的系统架构 阅读本文大约需要花费10分钟. 文章首发微信公众号:IngresGe 专注于Android系统级源码分析,Android的平台设计,欢迎关注我,谢谢! 欢 ...

  3. android 服务端技术,移动应用服务器端开发(基于JSP技术)-2017 Android系统构架 Android系统构架.docx...

    Android系统构架 PAGE 1 目 录 TOC \o "1-3" \h \z \u 一.Android系统构架 1 二.Linux内核层 2 三.系统运行库层 3 (一)系统 ...

  4. 【android系统】android系统升级流程分析(二)---update升级包分析

    接下来我们将通过几篇文章来分析update.zip包在具体Android系统升级的过程,来理解Android系统中Recovery模式服务的工作原理.今天让我先来分析下升级包update.zip. 一 ...

  5. 【android系统】android系统升级流程分析(一)---recovery模式中进行update包升级流程分析

    今天我们直接来看下android中具体的升级过程是如何的. 升级流程概述 升级的流程图: 升级流程分析 第一步:升级包获取 升级获取可以通过远程下载,也可直接拷贝到指定目录即可. 第二步:准备升级 然 ...

  6. android系统 PowerManager深入分析(非常详细)

    概述 一直以来,电源管理是电子产品设计中非常重要的环节,也是任何电子设备中最为重要的系统模块之一,优秀的电源管理方案,能够提供持久的续航能力,良好的用户体验,更能提升电子产品的竞争力. 移动设备的电量 ...

  7. android系统语音合成,android 语音合成报错

    发现了2个问题 第一个貌似是复制离线的资源出错了(已经核对过读写等权限): 12-19 19:54:49.739 32006-32159/com.zhanglf.youxuanz I/NonBlock ...

  8. Android 系统(71)---Android系统build.prop文件生成过程

    Android系统build.prop文件生成过程 Android系统build.prop生成过程 这个文件类似于windows的注册表文件,定义了系统初始的一些参数属性,功能的开放等,通过调整或增加 ...

  9. android系统平台,Android系统平台 实用小软件推荐

    随着时间的推移,android平台上的软件可谓是越来越丰富;每天各种千奇百怪的.实用的.趣味恶搞的应用层出不穷,要选择一个自己需要的合适自己手机用的软件真是越来越难了.为了各位手机用户们的手机寿命着想 ...

最新文章

  1. 512 个 AI 职位、11 万美元年薪,盘点 2018 最佳人工智能公司
  2. noi99钉子和小球 解题报告
  3. 【Servlet】总结 JSP的四大域对象、Servlet的四个作用域:pageContext、request、session、application
  4. 世界上覆盖范围最广的计算机网络是 ( ),世界上覆盖范围最广的计算机网络是()。...
  5. 【原】让两个DIV高度一样的Javascript函数
  6. 零基础 5 分钟上手,程序员喜提 AIoT 新利器!
  7. 毕业一年后我转行NLP 这几点宝贵经验分享给大家
  8. 深圳40K都招不到嵌入式开发人员?
  9. android解析html新闻的方法,Android使用Jsoup解析Html表格的方法
  10. depends-on
  11. HP Proliant DL360 G9使用业务网卡登录ILO管理
  12. linux万能密码,Linux pam 后门纪录root用户密码以及设置万能密码登录root
  13. python判断是否闰年_【python】判断年份是否为闰年
  14. 如何用电脑下载网页中的视频?
  15. 《吊打面试官》系列-Redis基础
  16. C语言的s8数据结构
  17. 【MT19937】学习分析
  18. B-spline曲线基函数计算Matlab程序
  19. 身高体重排序-华为OD
  20. c语言里主函数指什么,C语言里的主函数是什么

热门文章

  1. STM32学习——EXTI外部中断
  2. 【STM32】HAL库 STM32CubeMX教程五----看门狗(独立看门狗,窗口看门狗)
  3. Java学习日报—泳道与Feign—2021/11/30
  4. 令牌桶算法和漏桶算法python_图解Python算法
  5. 最长回文子串java_5. 最长回文子串
  6. 英文简历中的自我评价
  7. Alley Bird 跳跳鸟源码
  8. 关于火狐浏览器在ubuntu和安卓手机上的同步
  9. Hibernate操作数据库步骤(包括语法)
  10. Linux下部署LVS(DR)+keepalived+Nginx负载均衡