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相关推荐

  1. android handlerthread 线程管理,Android多线程之HandlerThread源码解析

    一.概述 先来了解一下HandlerThread的几个特性 HandlerThread继续于Thread,本身就是一个线程类 HandlerThread在内部维护了自己的Looper对象,所以可以进行 ...

  2. android handlerthread 线程管理,Android线程之HandlerThread

    概述 HandlerThread是Thread的一个子类,是Android中提供的另一种线程形态. Handy class for starting a new thread that has a l ...

  3. android 内核内存管理,Android内核相关内容总结

    要想充分掌握Android这一操作系统的应用,首先需要我们从Android内核的相关内容开始了解.在这里就为大家详细介绍一下相关的知识. Android操作系统是由谷歌推出的一款基于Linux平台开源 ...

  4. android的线程管理器,[Android开源]:一款安全、轻巧、简单的线程池管理器EasyThread...

    EasyThread通过对原生的线程池进行封装,可让你更方便的进行线程任务操作. 特性 简单轻巧:方法数不过百,无额外次级依赖. 配置灵活:可方便.灵活的对每次所启动的任务,配置线程名.线程优先级等. ...

  5. Android pms权限管理,Android权限机制

    为什么有权限机制 我们知道 Android 应用程序是沙箱隔离的,每个应用都有一个只有自己具有读写权限的专用数据目录.但是如果应用要访问别人的组件或者一些设备上全局可访问的资源,这时候权限机制就能系统 ...

  6. Android P 电量管理,Android P亮点汇总:更智能 更简单

    在今天早些时候开幕的 I/O 开发者大会上,谷歌正式宣布了 Android P 系统.本次更新主打智能,简单,让用户享受更健康的数字生活.具体来说有哪些更新呢?跟随小编一起来看看吧. 全新手势操作 优 ...

  7. android 获取权限管理,Android常用权限获取和设置

    Android常用权限获取和设置 1 活动管理器 权限 代码 ActivityManager activityManager = (ActivityManager) getSystemService( ...

  8. android系统 通知管理,Android的通知系统

    Android的通知系统 默认分类 | 2015-07-07 08:21:24 | 阅读 1581 次 | 评论(0) : 将应用程序的一些重要信息通知给用户. 1.Toast 形式:一般在界面下半部 ...

  9. android 生命周期管理,Android Activity生命周期和堆栈管理的详解_Android_脚本之家...

    Activity的生命周期 Activity是Android中的四大组件之一,也是最基本,最重要的组件,是android系统提供一个可视化的,能与用户交换的组件. 系统提供的组件,不需要用户实例化,用 ...

最新文章

  1. Centos Docker安装、升级、卸载
  2. 计算机应用基础作业北语,北语计算机应用基础作业.doc
  3. eclipse无法运行 ,报错:the selection cannot be launched
  4. 精简JRE第一步 — 精简bin目录
  5. ubuntu下面markdown转化为word文档
  6. C语言的标识符由什么组成
  7. nlp 命名实体识别 算法_中文命名实体识别算法 Lattice LSTM
  8. JAVA可不可以编写应用程序_编写一个java应用程序
  9. C语言课后习题(35)
  10. Closure--1
  11. Mysql查询高速缓存区
  12. Java回调函数实例
  13. 一起来作画吧「GitHub 热点速览 v.22.14」
  14. 4.29 笔记+day7作业
  15. 如何使用Zend Expressive建立NASA照片库
  16. 《excel应用大全》(excel home 编著)--学习摘抄笔记2
  17. 多个wordpress共享用户信息、共享Cookie
  18. 【C语言】a+aa+aaa+...+aa...a=?
  19. 如何将pdf等非标准数据文件转换成可供EXCEL等软件分析的数据
  20. 怎么申请好用的企业邮箱?外贸公司企业邮箱托管

热门文章

  1. TCP/IP 数据链路层详解 广播信道局域网网络
  2. 安装ansys的mpi
  3. php $stri.=$v 是什么意思,php – 我的str_replace代码不起作用
  4. 【每周一本书】之《深度学习核心技术与实践》:“小猿搜题”团队倾力之作
  5. IOS APP 证书申请 及 打包ipa包
  6. 用python爬取开放数据
  7. 全国前三季度农产品生产价格同比上涨19.1%
  8. Scrapy 2.6.2 代理设置,Proxy-Authorization 安全漏洞修复
  9. mysql bdb_MySQL在Red Hat 7.0上的BDB表配置
  10. 国内自然语言处理研究组