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

2018-02-09 12:39:56来源:http://blog.csdn.net/carson_ho/article/details/79285760作者:CSDN人点击

分享
前言

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


继承Thread类
实现Runnable接口
Handler
AsyncTask
HandlerThread

今天,我将全面解析多线程其中一种常见用法:HandlerThread



由于本文涉及多线程知识和Handler源码解析,所以阅读本文前建议先看:


Android开发:Handler异步通信机制全面解析(包含Looper、Message Queue)
目录


1. 定义

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


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() ) {
@Override
public 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 实例说明
点击按钮实现延迟操作
最终更新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;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 显示文本
text = (TextView) findViewById(R.id.text1);
// 创建与主线程关联的Handler
mainHandler = 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){
// 消息1
case 1:
try {
//延时操作
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 通过主线程Handler.post方法进行在主线程的UI更新操作
mainHandler.post(new Runnable() {
@Override
public void run () {
text.setText("我爱学习");
}
});
break;
// 消息2
case 2:
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
mainHandler.post(new Runnable() {
@Override
public void run () {
text.setText("我不喜欢学习");
}
});
break;
default:
break;
}
}
};
/**
* 步骤4:使用工作线程Handler向工作线程的消息队列发送消息
* 在工作线程中,当消息循环时取出对应消息 & 在工作线程执行相关操作
*/
// 点击Button1
button1 = (Button) findViewById(R.id.button1);
button1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 通过sendMessage()发送
// a. 定义要发送的消息
Message msg = Message.obtain();
msg.what = 1; //消息的标识
msg.obj = "A"; // 消息的存放
// b. 通过Handler发送消息到其绑定的消息队列
workHandler.sendMessage(msg);
}
});
// 点击Button2
button2 = (Button) findViewById(R.id.button2);
button2.setOnClickListener(new View.OnClickListener() {
@Override
public 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() {
@Override
public void onClick(View v) {
mHandlerThread.quit();
}
});
}
}
运行结果


源码地址

Carson_Ho的Github:HandlerThread
6.3 特别注意点
细节问题1:内存泄露
在上面的例子中,出现了严重的警告:
In Android, Handler classes should be static or leaks might occur.
即造成了严重的 内存泄漏 ,关于Handler的内存泄露请看文章: Android 内存泄露:详解 Handler 内存泄露的原因
细节问题2:连续发送消息
当你连续点击3下时,发现并无按照最新点击的按钮操作显示,而是按顺序的一个个显示出来
原因:使用 HandlerThread 时只是开了一个工作线程,当你点击了 n 下后,只是将 n 个消息发送到消息队列 MessageQueue 里排队,等候派发消息给Handler再进行对应的操作
7. 源码分析
知其然 而须知其所以然,了解 HandlerThread 的源码分析有利于更好地理解 HandlerThread 的工作原理
具体请看文章: Android多线程:这是一份详细的HandlerThread源码分析攻略

8. 总结
本文全面介绍了多线程 HandlerThread 的用法 & 源码
接下来,我会继续讲解 Android 开发中关于多线程的知识,包括继承 Thread 类、实现 Runnable 接口、 Handler 等等,有兴趣可以继续关注 Carson_Ho的安卓开发笔记
请帮顶 / 评论点赞!因为你的鼓励是我写作的最大动力!

最新文章

123

最新摄影

闪念基因

微信扫一扫

第七城市微信公众平台