Android HandlerThread案例详解
作者:tandeneck 发布时间:2022-04-20 09:46:25
标签:Android,HandlerThread
HandlerThread 顾名思义就是一种可以使用 Handler 的 Thread。日常开发中我们经常会通过创建一个 Thread 去执行任务,有多个任务就多创建几个线程实现,这时候可能出现线程同步的问题。不过有时候我们并不需要很强的并发性,只需保证按照顺序地执行各个任务即可,有什么好办法实现呢?第一反应想到的可能是通过 Executors.newSingleThreadExecutor() 方法来创建一个 SingleThreadExecutor,来统一所有的任务到一个线程中,然后按顺序执行。其实,除了这个方法之外,HandlerThread 也可以实现。
简单使用
首先创建一个 HandlerThreadActivity
public class HandlerThreadActivity extends BaseActivity {
private static final String TAG = "HandlerThreadActivity";
private Button mStartBtn;
private Handler mHandler;
private HandlerThread mHandlerThread;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_handler_thread);
mStartBtn = findViewById(R.id.start_btn);
mHandlerThread = new HandlerThread("THREAD_NAME");
mHandlerThread.start();
mHandler = new Handler(mHandlerThread.getLooper());
mStartBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mHandler.post(new Runnable() {
@Override
public void run() {
Log.d(TAG, Thread.currentThread().getId() + " " + String.valueOf((Looper.myLooper() == Looper.getMainLooper())) + " 任务:" + this.hashCode());
SystemClock.sleep(3000);
}
});
}
});
}
@Override
protected void onDestroy() {
super.onDestroy();
mHandlerThread.quit();
}
}
快速三击按钮,打印日志如下:
可以发现,三次不同的任务按开始的顺序执行,而且是运行在子线程中,那到底是怎么实现的呢?
源码解析
public class HandlerThread extends Thread {
int mPriority;
int mTid = -1;
Looper mLooper;
private @Nullable Handler mHandler;
public HandlerThread(String name) {
super(name);
mPriority = Process.THREAD_PRIORITY_DEFAULT;
}
public HandlerThread(String name, int priority) {
super(name);
mPriority = priority;
}
protected void onLooperPrepared() {
}
@Override
public void run() {
// 获取线程 id
mTid = Process.myTid();
//构建一个 Looper
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
//设置线程优先级
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
// Looper 循环
mTid = -1;
}
// 获取当前线程的 Looper,
public Looper getLooper() {
if (!isAlive()) {
return null;
}
synchronized (this) {
while (isAlive() && mLooper == null) {
try {
wait();
} catch (InterruptedException e) {
}
}
}
return mLooper;
}
/**
* @return a shared {@link Handler} associated with this thread
* @hide 方法隐藏掉,无法调用
*/
@NonNull
public Handler getThreadHandler() {
if (mHandler == null) {
mHandler = new Handler(getLooper());
}
return mHandler;
}
//线程退出方法,主要是调用 Looper.quit() 方法,不然一直在循环
public boolean quit() {
Looper looper = getLooper();
if (looper != null) {
looper.quit();
return true;
}
return false;
}
//同上,不过这个方法会把消息队列中的已有消息处理完才会安全地退出
public boolean quitSafely() {
Looper looper = getLooper();
if (looper != null) {
looper.quitSafely();
return true;
}
return false;
}
public int getThreadId() {
return mTid;
}
}
通读下来,如果熟悉 Handler 原理的同学大概就明白 HandlerThread 的机制了:
HandlerThread 运行 start() 方法,回调 run() 方法。
在 run() 方法中通过 Looper.prepare() 来创建消息队列,并通过 Looper.looper() 方法来开启消息循环。
由于 Loop.loop() 是一个死循环,导致 run() 也是无线循环,因此当我们不需要使用 HandlerThread 的时候,要调用它的 quit() 方法或者 quiteSafely() 方法。
来源:https://www.jianshu.com/p/9807338a38c3


猜你喜欢
- 1.类的6个默认成员函数默认成员函数:用户没有显示实现,编译器会生成的成员函数称为默认成员函数。如果一个类中什么成员都没有,简称为空类。但空
- 废话不多说,上代码String basePath = request.getScheme()+"://"+request
- 本文实例讲述了Java Scanner类用法及nextLine()产生的换行符问题。分享给大家供大家参考,具体如下:分析理解:Scanner
- 本文为大家分享了Android Toast全屏显示的具体代码,供大家参考,具体内容如下废话不说,直接上代码:private void toa
- 场景在任何一个Form表单的操作页面或者数据台账的查询页面,基本都会看到一个清除的按钮,其功能就是用来清除我们需要抛弃的已经写入到控件内的数
- 目的:使用Fleck框架实现网页与服务端实时通信传统的网站采用http方式与服务端通信,属于请求响应模式,如何让网页与服务器之间能使用TCP
- 最近出现一个问题是这样的:我们的系统在国外打印的日志时间由于时差关系和国内不一致,看起来不方便,希望国外的日志和国内保持一致,即:需要对不同
- C# 输出参数out什么是输出参数方法声明时,使用out修饰符声明的形参,成为输出参数。输出参数的特点1、输出参数不创建新的储存位置。2、输
- 不需要AIDL也不需要复杂的ContentProvider,也不需要SharedPreferences或者共享存储文件!只需要简单易懂的Me
- 本文实例讲述了C#动态调用事件的方法。一般来说,传统的思路是,通过Reflection.EventInfo获得事件的信息,然后使用GetRa
- 以下代码为一个工具类package com.imooc.reflect;import java.lang.reflect.Method;pu
- 这里给一个样例树:代码:#include <stdio.h> #include <string.h>#include
- 经测试,是环绕通知改变了返回值,切面方法需要有返回值,来代替被代理方法返回结果改成如下即可:@Around("point_upda
- 本人一直使用的是Eclipse作为开发工具的,不过现在IDEA非常的受推崇,所以决定上手试一试。网上有很多旗舰版的文章,我没有仔细看,我这次
- 目录int和Integer的区别及自动装箱和自动拆箱Integer和int的对比,如下所示:自动装箱和自动拆箱:Integer的自动拆装箱的
- execution (常用,方法级别的匹配)语法:execution(modifiers-pattern? ret-type-pattern
- webclient在调用DownloadData或者DownloadString的时候请求回来的数据出现乱码问题,解决办法如下:1、设置we
- 一、案例一//XML文件写方法 //编写XML文件的格式并存储到指定的FilePath
- 这两种方式也是大家在日常编码工作当中用的比较多的判断方式、之前在使用的时候也没太关注两者在比较不同类型的时候存在哪些区别今天就和大家一起深入
- 使用Java的方式配置Spring我们现在要完全不使用Spring的xml配置,全权使用Java来配置Spring!JavaConfig是S