android HandlerThread源码解析
尊重原创,转载请注明出处:http://blog.csdn.net/a740169405/article/details/50257001
HandlerThread概述:
- HandlerThread是一个线程类。
- HandlerThread内部创建了一个消息队列,其他线程可以通过Handler向其发送消息。
- HandlerThread按照消息的发送顺序依次对消息进行处理。
- HandlerThread在所有消息执行完毕后,线程并不会自动退出,消息队列任然在等待新任务。
一、HandlerThread内部消息队列的初始化:
在线程成功执行后,HandlerThread创建了一个消息队列,用来接收其他线程发来的消息:
@Override
public void run() {mTid = Process.myTid();// 为当前线程创建LooperLooper.prepare();synchronized (this) {// 获取当前线程Looper对象mLooper = Looper.myLooper();// 唤醒其他等待线程notifyAll();}Process.setThreadPriority(mPriority);// mLooper对象初始化完成后回调onLooperPrepared();// 开始循环读取消息队列里的消息Looper.loop();mTid = -1;
}
该方法调用了Looper.prepare();创建了一个消息队列。这样,该线程就能接收handler发送的消息了。
最后调用了Looper.loop();开始循环读取消息。
二、向HandlerThread发送消息:
@Override
protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);// 创建线程,命名为"myHandlerThread"HandlerThread handlerThread = new HandlerThread("myHandlerThread");// 启动线程handlerThread.start();// 创建Handler,并指定使用HandlerThread的消息队列来处理消息MyHandler myHandler = new MyHandler(handlerThread.getLooper());// 发送一条空消息给消息队列myHandler.obtainMessage().sendToTarget();}public static class MyHandler extends Handler {public MyHandler(Looper looper) {super(looper);}@Overridepublic void handleMessage(Message msg) {super.handleMessage(msg);// 收到消息后,打印出当前线程的名字Log.e(TAG, "current Thread name : " + Thread.currentThread().getName());}
}
我在主线程中初始化了一个HandlerThread线程,并启动了该线程。
向HandlerThread的消息队列发送了一条消息,消息收到后输出了当前线程的名字。
demo.chen.com.myapplication E/HandlerThreadActivity: current Thread name : myHandlerThread
后台输出的名字正是我创建线程的时候传递进去的。
通过上面的例子我们发现,向handlerThread发送的消息,是由HandlerThread线程来处理的。
三、HandlerThread锁机制:
大家注意这一段代码:
synchronized (this) {mLooper = Looper.myLooper();notifyAll();
}
加锁是为了确保其他现成获取该线程的Looper时不为空。
我们再看看HandlerThread提供的获取Looper的方法:
public Looper getLooper() {// 如果线程未启动,返回空if (!isAlive()) {return null;}// If the thread has been started, wait until the looper has been created.synchronized (this) {while (isAlive() && mLooper == null) {try {// 如果线程已启动,并且消息队列尚未初始化,进入等待状态wait();} catch (InterruptedException e) {}}}return mLooper;}
代码的意思很简单,如果Looper还未创建,则进入等待状态,直到Looper被创建。
我尝试写一个HandlerThread的子类来验证一下:
public static class MyHandlerThread extends HandlerThread {public MyHandlerThread(String name) {super(name);}@Overridepublic void run() {try {// 在线程启动后,初始化消息队列之前,sleep三秒Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}// 调用父类的run方法初始化消息队列super.run();}@Overridepublic Looper getLooper() {return super.getLooper();}
}
逻辑很简单,重写run方法,在调用父类run方法进行Looper初始化之前让线程sleep三秒。
添加一些Log:
MyHandlerThread handlerThread = new MyHandlerThread("myHandlerThread");
// 线程启动前,先打个log记录当前时间
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Log.e(TAG, "current time = " + formatter.format(new Date()));
handlerThread.start();
Looper looper = handlerThread.getLooper();
// 在getLooper();之后打印log记录当前时间
Log.e(TAG, "get looper success, send message, time = " + formatter.format(new Date()));
MyHandler myHandler = new MyHandler(looper);
// 发送消息
myHandler.obtainMessage().sendToTarget();
再看看log:
E/HandlerThreadActivity: current time = 2015-12-11 08:45:03
E/HandlerThreadActivity: get looper success, send message, time = 2015-12-11 08:45:06
E/HandlerThreadActivity: current Thread name : myHandlerThread
从log中可以看出主线程等待了三秒,之所以加锁是为了防止在looper未被初始化之前,其他线程调用getLooper方法得到空对象。
注意:
一般我们是不需要重写HandlerThread类,只需要使用Handler对象向HandlerThread的消息队列发送消息,在handleMessage函数里处理消息,就可以了,且处理消息的线程是HandlerThread这个线程。
上面的例子中,我在消息队列初始化之前sleep了3秒,导致了主线程在getLooper的时候等待了3秒,也就是说有可能造成主线程ANR。
四、HandlerThread的退出
需要注意的是,一旦执行Looper.loop();线程便进入循环获取消息状态,也就是说线程不会自己停止,我们可以一直往线程发送消息,如果需要停止线程,只要调用HandlerThread对象的quit();或者quitSafely();函数,这两个函数其实只是调用了Looper对象的quit();或者quitSafely();函数:
HandlerThread的quit();函数:
public boolean quit() {// 获取当前线程的LooperLooper looper = getLooper();if (looper != null) {// 立即停止Looper的循环,不在处理未处理完的消息looper.quit();return true;}return false;
}
HandlerThread的quitSafely();函数:
public boolean quitSafely() {// 获取当前线程的LooperLooper looper = getLooper();if (looper != null) {// 打上需要停止循环的标志,等到消息都处理完以后,再推出循环looper.quitSafely();return true;}return false;
}
这两者的区别在于,调用quit();会直接终止消息队列的循环,如果队列中还有其他消息未处理,将不会被处理。
而调用quitSafely();函数则是给消息队列打上退出循环的标记,在所有消息处理完成以后,Looper自动退出循环,从而线程也就会结束。
总结:
1. HandlerThread类是google提供的一个,在线程内创建消息循环队列的线程API,让除了主线程以外的子线程也具有消息处理能力。
2. 使用时记得先调用HandlerThread的run方法启动线程
3. 在创建Handler时使用HandlerThread的Looper对象。
4. 确认所有任务都处理完成以后,记得调用HandlerThread推出函数,建议使用quitSafely();这样会等到所有消息都处理完后再推出线程。
应用:
HandlerThread在IntentService中应用到。
关于IntentService的项管内容,大家可以阅读我的另一片博客:Android IntentService的使用与源码解析
android HandlerThread源码解析相关推荐
- Android Lifecycle源码解析(一)
Android Lifecycle源码解析(一) 首先我们看HomeActivity中我们添加到一行代码 public class HomeActivity extends AppCompatActi ...
- 【Android】Android Broadcast源码解析
Android Broadcast源码解析 一.静态广播的注册 静态广播是通过PackageManagerService在启动的时候扫描已安装的应用去注册的. 在PackageManagerServi ...
- Android xUtils3源码解析之图片模块
本文已授权微信公众号<非著名程序员>原创首发,转载请务必注明出处. xUtils3源码解析系列 一. Android xUtils3源码解析之网络模块 二. Android xUtils3 ...
- 【Android】Android Parcelable 源码解析
Android Parcelable 源码解析 大家都知道,要想在Intent里面传递一些非基本类型的数据,有两种方式,一种实现Parcelable,另一种是实现Serializable接口.今天先不 ...
- Android xUtils3源码解析之注解模块
本文已授权微信公众号<非著名程序员>原创首发,转载请务必注明出处. xUtils3源码解析系列 一. Android xUtils3源码解析之网络模块 二. Android xUtils3 ...
- Android xUtils3源码解析之数据库模块
本文已授权微信公众号<非著名程序员>原创首发,转载请务必注明出处. xUtils3源码解析系列 一. Android xUtils3源码解析之网络模块 二. Android xUtils3 ...
- [Android] Handler源码解析 (Java层)
之前写过一篇文章,概述了Android应用程序消息处理机制.本文在此文基础上,在源码级别上展开进行概述 简单用例 Handler的使用方法如下所示: Handler myHandler = new H ...
- android sdk 源码解析
AndroidSdkSourceAnalysis:https://github.com/LittleFriendsGroup/AndroidSdkSourceAnalysis 第一期 Class 分析 ...
- Android LayoutInflater源码解析:你真的能正确使用吗?
版权声明:本文出自汪磊的博客,未经作者允许禁止转载. 好久没写博客了,最近忙着换工作,没时间写,工作刚定下来.稍后有时间会写一下换工作经历.接下来进入本篇主题,本来没想写LayoutInflater的 ...
- Android HandlerThread 源码分析
HandlerThread 简介: 我们知道Thread线程是一次性消费品,当Thread线程执行完一个耗时的任务之后,线程就会被自动销毁了.如果此时我们又有一 个耗时任务需要执行,我们不得不重新创建 ...
最新文章
- ubuntu 14.04 mysql 5.7_ubuntu14.04 升级mysql到5.7版本
- Go 语言读写 Excel
- android冒烟测试自动化,自动化冒烟测试脚本应当遵循的原则
- 【论文解读】NLP重铸篇之Word2vec
- linux 挂载exfat u盘 yum,centos挂载exfat u盘
- 套接字编程--1(UDP协议编程,端口号,传输层协议,网络字节序)
- linux常用网络命令ping和arping
- CentOS 7 上搭建 ZooKeeper 集群
- c#---params参数
- js中的数组和字符串的一些方法
- 上传图片方法大全 [网摘]
- 在windows下把txt文件改为utf8格式
- html设计效果图,网页效果图如何制作?
- uc android快捷键,UC手机浏览器助力Android快速上网
- Python3简单的爬虫项目 爬取虎牙主播名字 人气
- 液滴模板水凝胶的温度控制形状变化(定制PNIPA/膨润土复合水凝胶/聚乙烯醇/魔芋胶复合凝胶/海藻酸钠(SA)/氧化石墨烯(GO)复合水凝胶/壳聚糖(CS)-g-PAM/氧化石墨烯(GO)复合水凝胶)
- 干货|科技赋能财富硬核直播带货,助力宜信财富逆势增长
- 计算两个日期之间所间隔天数的快速算法
- 老枪的59条制胜法则
- [K210]Maixpy self learning classifier 自学习分类器