android handlerthread 线程管理,Android必读之HandlerThread
HandlerThread是Thread的子类,主要特点就是为我们主动封装了Looper,这样我们就可以和Handler结合在一起使用,利用Handler的消息机制原理为我们更加有序高效的管理Thread通信和其它逻辑,这也为什么我们通常在自定义的Thread中使用Handler的原因。
首先我们先了解一下自定义Thread如何使用Handler,下面是完整Kotlin代码:
class MyThread() : Thread() {
var handler: Handler? = null;
override fun run() {
super.run()
Looper.prepare();//准备looper
initHandler();
//处理耗时操作,比如请求API,大量数据读写等
Log.d("MyThread", "MyThread-开始处理耗时逻辑");
getWeather()
//开始处理消息,确保在loop方法放在最后,因为这是无限循环,后面的代码不会执行
//当调用mHandler.getLooper().quit()后,loop才会中止,其后的代码才能得以运行
//逻辑运行完成后调用quit或者quitSafely退出,否则会造成这个Thread会一直运行,从而造成内存泄露
Looper.loop();
}
fun initHandler() {
handler = Handler(object : Handler.Callback {
override fun handleMessage(msg: Message?): Boolean {
when (msg!!.what) {
0 -> {
Log.d("MyThread", "MyThread-Success");
handler!!.sendEmptyMessage(2)
}
1 -> {
Log.d("MyThread", "MyThread-Failed");
handler!!.sendEmptyMessage(2)
}
2 -> {
Log.d("MyThread", "MyThread-结束");
handler!!.looper.quitSafely();
}
}
return true;
}
})
}
fun getWeather() {
var response = HttpUtils.getInstance().requestWeather();
if (response != null) {
var result: String = response.body()!!.string();
Log.d("MyThread", result);
handler!!.sendEmptyMessage(0)
} else {
handler!!.sendEmptyMessage(1)
}
}
}
新建的Thread中没有Looper,需要我们指定或者使用Looper.prepare()新建一个,看一下prepare的源码就知道了:
public static void prepare() {
prepare(true);
}
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));//新建Looper
}
如果没有指定Looper就创建Handler会报以下Exception:
java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
at android.os.Handler.(Handler.java:204)
at android.os.Handler.(Handler.java:132)
总结以上代码我们发现如果我们在自定义的Thread中使用Handler需要我们主动去实现Looper相关的功能,还是比较麻烦的,所以Android已经为我准备了HandlerThread类,已经封装好了Looper的逻辑,看一下Handler Thread中run方法的源码:
@Override
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
Handler Thread使用起来也非常简单:
//var为可变变量 和val为常量相当于final
val handlerThread = HandlerThread("MyHandler");
var handler: Handler? = null;
fun initHandlerThread() {
handlerThread.start();
val looper = handlerThread.looper;
//handler运行在handlerThread线程中,不能直接操作UI
handler = object : Handler(looper) {
override fun handleMessage(msg: Message?) {
super.handleMessage(msg)
when (msg!!.what) {
0 -> {
getWeather()
}
1 -> {
Log.d("HandlerThread", "HandlerThread-退出");
handlerThread.quitSafely()//安全推送线程
}
}
}
};
}
/**
* 因为getWeather方法运行在handlerThread线程中,所以不用担心ANR,使用同步方式请求API
*/
fun getWeather() {
var response = HttpUtils.getInstance().requestWeather();
if (response != null) {
var result: String = response.body()!!.string();
Log.d("HandlerThread", result);
}
handler!!.sendEmptyMessage(1)
}
在使用HandlerThread时我们一定要注意需要我们及时退出Looper,否则容易造成内存泄露。Looper退出的方法有两个quit和quitSafely,HandlerThread中源码如下:
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;
}
再看一下Looper中的源码:
public void quit() {
mQueue.quit(false);
}
public void quitSafely() {
mQueue.quit(true);
}
都是调用MessageQueue的quit的方法,只不过一个传了false,一个传了true,区别就是quit方法会将消息队列中的所有消息移除(延迟消息和非延迟消息)。
quitSafely会将消息队列所有的延迟消息移除,非延迟消息派发出去让Handler去处理。quitSafely相比于quit方法安全之处在于清空消息之前会派发所有的非延迟消息。如果有兴趣可以参考一下下面的源码:
void quit(boolean safe) {
if (!mQuitAllowed) {
throw new IllegalStateException("Main thread not allowed to quit.");
}
synchronized (this) {
if (mQuitting) {
return;
}
mQuitting = true;
if (safe) {
removeAllFutureMessagesLocked();
} else {
removeAllMessagesLocked();
}
// We can assume mPtr != 0 because mQuitting was previously false.
nativeWake(mPtr);
}
}
private void removeAllMessagesLocked() {
Message p = mMessages;
while (p != null) {
Message n = p.next;
p.recycleUnchecked();
p = n;
}
mMessages = null;
}
private void removeAllFutureMessagesLocked() {
final long now = SystemClock.uptimeMillis();
Message p = mMessages;
if (p != null) {
if (p.when > now) {
removeAllMessagesLocked();
} else {
Message n;
for (;;) {
n = p.next;
if (n == null) {
return;
}
if (n.when > now) {
break;
}
p = n;
}
p.next = null;
do {
p = n;
n = p.next;
p.recycleUnchecked();
} while (n != null);
}
}
}
android handlerthread 线程管理,Android必读之HandlerThread相关推荐
- android handlerthread 线程管理,Android多线程之HandlerThread源码解析
一.概述 先来了解一下HandlerThread的几个特性 HandlerThread继续于Thread,本身就是一个线程类 HandlerThread在内部维护了自己的Looper对象,所以可以进行 ...
- android handlerthread 线程管理,Android线程之HandlerThread
概述 HandlerThread是Thread的一个子类,是Android中提供的另一种线程形态. Handy class for starting a new thread that has a l ...
- android 内核内存管理,Android内核相关内容总结
要想充分掌握Android这一操作系统的应用,首先需要我们从Android内核的相关内容开始了解.在这里就为大家详细介绍一下相关的知识. Android操作系统是由谷歌推出的一款基于Linux平台开源 ...
- android的线程管理器,[Android开源]:一款安全、轻巧、简单的线程池管理器EasyThread...
EasyThread通过对原生的线程池进行封装,可让你更方便的进行线程任务操作. 特性 简单轻巧:方法数不过百,无额外次级依赖. 配置灵活:可方便.灵活的对每次所启动的任务,配置线程名.线程优先级等. ...
- Android pms权限管理,Android权限机制
为什么有权限机制 我们知道 Android 应用程序是沙箱隔离的,每个应用都有一个只有自己具有读写权限的专用数据目录.但是如果应用要访问别人的组件或者一些设备上全局可访问的资源,这时候权限机制就能系统 ...
- Android P 电量管理,Android P亮点汇总:更智能 更简单
在今天早些时候开幕的 I/O 开发者大会上,谷歌正式宣布了 Android P 系统.本次更新主打智能,简单,让用户享受更健康的数字生活.具体来说有哪些更新呢?跟随小编一起来看看吧. 全新手势操作 优 ...
- android 获取权限管理,Android常用权限获取和设置
Android常用权限获取和设置 1 活动管理器 权限 代码 ActivityManager activityManager = (ActivityManager) getSystemService( ...
- android系统 通知管理,Android的通知系统
Android的通知系统 默认分类 | 2015-07-07 08:21:24 | 阅读 1581 次 | 评论(0) : 将应用程序的一些重要信息通知给用户. 1.Toast 形式:一般在界面下半部 ...
- android 生命周期管理,Android Activity生命周期和堆栈管理的详解_Android_脚本之家...
Activity的生命周期 Activity是Android中的四大组件之一,也是最基本,最重要的组件,是android系统提供一个可视化的,能与用户交换的组件. 系统提供的组件,不需要用户实例化,用 ...
最新文章
- Centos Docker安装、升级、卸载
- 计算机应用基础作业北语,北语计算机应用基础作业.doc
- eclipse无法运行 ,报错:the selection cannot be launched
- 精简JRE第一步 — 精简bin目录
- ubuntu下面markdown转化为word文档
- C语言的标识符由什么组成
- nlp 命名实体识别 算法_中文命名实体识别算法 Lattice LSTM
- JAVA可不可以编写应用程序_编写一个java应用程序
- C语言课后习题(35)
- Closure--1
- Mysql查询高速缓存区
- Java回调函数实例
- 一起来作画吧「GitHub 热点速览 v.22.14」
- 4.29 笔记+day7作业
- 如何使用Zend Expressive建立NASA照片库
- 《excel应用大全》(excel home 编著)--学习摘抄笔记2
- 多个wordpress共享用户信息、共享Cookie
- 【C语言】a+aa+aaa+...+aa...a=?
- 如何将pdf等非标准数据文件转换成可供EXCEL等软件分析的数据
- 怎么申请好用的企业邮箱?外贸公司企业邮箱托管
热门文章
- TCP/IP 数据链路层详解 广播信道局域网网络
- 安装ansys的mpi
- php $stri.=$v 是什么意思,php – 我的str_replace代码不起作用
- 【每周一本书】之《深度学习核心技术与实践》:“小猿搜题”团队倾力之作
- IOS APP 证书申请 及 打包ipa包
- 用python爬取开放数据
- 全国前三季度农产品生产价格同比上涨19.1%
- Scrapy 2.6.2 代理设置,Proxy-Authorization 安全漏洞修复
- mysql bdb_MySQL在Red Hat 7.0上的BDB表配置
- 国内自然语言处理研究组