handlerthread
前言
-
多线程的应用在
Android
开发中是非常常见的,常用方法主要有:- 继承Thread类
- 实现Runnable接口
- handler
- AsyncTask
- handlerthread
-
今天,我将全面解析多线程其中一种常见用法:HandlerThread
由于本文涉及多线程知识和Handler源码解析,所以阅读本文前建议先看:
目录
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>
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.
细节问题2:连续发送消息
- 当你连续点击3下时,发现并无按照最新点击的按钮操作显示,而是按顺序的一个个显示出来
- 原因:使用
HandlerThread
时只是开了一个工作线程,当你点击了n
下后,只是将n
个消息发送到消息队列MessageQueue
里排队,等候派发消息给Handler再进行对应的操作
7. 源码分析
- 知其然 而须知其所以然,了解
HandlerThread
的源码分析有利于更好地理解HandlerThread
的工作原理 - 具体请看文章:Android多线程:这是一份详细的HandlerThread源码分析攻略
8. 总结
- 本文全面介绍了多线程
HandlerThread
的用法 & 源码 - 接下来,我会继续讲解
Android
开发中关于多线程的知识,包括继承Thread
类、实现Runnable
接口、Handler
等等,感兴趣的同学可以继续关注carson_ho的微信公众号
请帮顶 / 评论点赞!因为你的鼓励是我写作的最大动力!
相关阅读
改造Android手机为,便携式linux服务器,跑tomcat
环境设备1) 闲置安卓手机一部,我的是 oppoR7. 要获取root权限。如果总root失败可以刷下机。2) 可以开热点的 windows电脑一部,我的
金三银四到来了,找工作的好时候到了,小伙伴们是不是都在忙着找工作呢,小弟前一阵也是忙着在找工作,面试了好多公司,所幸的是进到了自己
【Android - 个人项目】— 地震管家(全球地震信息)
EarthQuakeApp.zip
Android Broadcast原理分析之registerReceiver(一)
目录 BroadcastReceiver概述 BroadcastReceiver分类 registerReceiver流程图 源码解析 总结 1. BroadcastReceiver概述 广播作
Android VelocityTracker类 滑动速度跟踪
VelocityTracker就是速度跟踪的意思。我们可以获得触摸点的坐标,根据按下的时间可以简单的计算出速度的大小。当你需要跟踪的时候