Android HandlerThread使用介绍以及源码解析
摘要: 版权声明:本文出自汪磊的博客,转载请务必注明出处。
一、HandlerThread的介绍及使用举例
HandlerThread是什么鬼?其本质就是一个线程,但是HandlerThread在启动的时候会帮我们准备好一个Looper,并供外界使用,说白了就是使我们在子线程中更方便的使用Handler,比如没有HandlerThread我们要在子线程使用Handler,写法如下:
private Handler mHandler;
@Override
public void run() {
super.run();
Looper.prepare();
mHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
}
};
Looper.loop();
}
有了HandlerThread就不用我们自己管理Looper了,至于为什么分析源码的时候就明白了。
HandlerThread使用简单介绍:
首先我们要初始化HandlerThread然后调用其start方法,也就是开启线程:
mHandlerThread = new HandlerThread("mHandlerThread");//这里的mHandlerThread其实就是线程的名字
mHandlerThread.start();
接下来初始化一个Handler并且将mHandlerThread中的Looper作为构造函数参数传递给Handler:
mHandler = new Handler(mHandlerThread.getLooper())
这样就保证了Hnadler运行在子线程。并且需要在适合的时机调用HandlerThread的quit方法或quitSafely方法,如Activity销毁的时候:
@Override
protected void onDestroy() {
//
super.onDestroy();
//释放资源
mHandlerThread.quit();
}
quit()与quitSafely()方法比较(这里只说一些结论,源码可以自己查看):
相同点:
调用之后MessageQueue消息队列均不在接受新的消息加入队列。
不同点:
quit方法把MessageQueue消息池中所有的消息全部清空。quitSafely方法只会清空MessageQueue消息池中所有的延迟消息(延迟消息是指通过sendMessageDelayed或postDelayed等方法发送的消息),非延迟消息则不清除继续派发出去让Handler去处理。
接下来我们完整看一下HandlerThread例子源码:
public class MainActivity extends Activity {
private HandlerThread mHandlerThread;
private Handler mHandler;
private boolean flag;
//
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mHandlerThread = new HandlerThread("mHandlerThread");
mHandlerThread.start();
mHandler = new Handler(mHandlerThread.getLooper()) {
@Override
public void handleMessage(Message msg) {
//
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
if(flag){
Log.i("HandlerThread", "更新:"+new Random().nextInt(1000));
}
mHandler.sendEmptyMessage(1);
}
};
}
@Override
protected void onResume() {
//
super.onResume();
flag = true;
mHandler.sendEmptyMessage(1);
}
@Override
protected void onPause() {
//
super.onPause();
flag = false;
}
@Override
protected void onDestroy() {
//
super.onDestroy();
//释放资源
mHandlerThread.quit();
}
}
运行程序就会在控制台看到每隔两秒有Log打出。至于HandlerThrea的使用就到此为止了,看懂上面小例子就差不多了。
二、HandlerThread的源码分析
HandlerThread源码非常简短,出去注释不到100行,这里就直接全部贴出来了:
public class HandlerThread extends Thread {
int mPriority;
int mTid = -1;
Looper mLooper;
public HandlerThread(String name) {
super(name);
mPriority = Process.THREAD_PRIORITY_DEFAULT;
}
/**
* Constructs a HandlerThread.
* @param name
* @param priority The priority to run the thread at. The value supplied must be from
* {@link android.os.Process} and not from java.lang.Thread.
*/
public HandlerThread(String name, int priority) {
super(name);
mPriority = priority;
}
/**
* Call back method that can be explicitly overridden if needed to execute some
* setup before Looper loops.
*/
protected void onLooperPrepared() {
}
@Override
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
/**
* This method returns the Looper associated with this thread. If this thread not been started
* or for any reason is isAlive() returns false, this method will return null. If this thread
* has been started, this method will block until the looper has been initialized.
* @return The 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;
}
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;
}
/**
* Returns the identifier of this thread. See Process.myTid().
*/
public int getThreadId() {
return mTid;
}
}
看第一行就知道了其本质就是一个线程。
6-9行以及17-20行构造函数,也很简单,就是初始化的时候我们可以定义线程名字,还可以传入线程优先级。
初始化完成,紧接着调用start()开发线程就会执行run方法逻辑。
30-41行代码,最重要的就是调用Looper.prepare()以及Looper.loop()方法为我们在子线程准备好一个Looper。并且用变量mLooper记录,调用getLooper()方法的时候返回。
但是,细心的你肯定发现run()方法中有个notifyAll(),getLooper()中有个wait()为什么要加这些鸟玩意?
大家发现没在HandlerThread 例子中Handler的创建是在主线程完成的,创建的时候需要调用HandlerThread的getLooper()获取mLooper作为参数传递给Handler的构造函数,而Looper的创建是在子线程中创建的,这里就有线程同步问题了,比如我们调用getLooper()的时候HandlerThread中run()方法还没执行完,mLooper变量还未赋值,此时就执行了wait()等待逻辑,一直等到run()方法中mLooper被赋值,之后立即执行notifyAll(),然后getLooper()就可以正确返回mLooper了。
明白了吧,不明的话这里需要花些时间好好理解下,好了源码主要部分就分析完了,看到这里相信你对HandlerThread有了一定的了解了。
HandlerThread 还是比较简单理解的,好了,本篇到此为止,希望对你有帮助。
Android HandlerThread使用介绍以及源码解析的更多相关文章
- Android IntentService使用介绍以及源码解析
版权声明:本文出自汪磊的博客,转载请务必注明出处. 一.IntentService概述及使用举例 IntentService内部实现机制用到了HandlerThread,如果对HandlerThrea ...
- IPerf——网络测试工具介绍与源码解析(4)
上篇随笔讲到了TCP模式下的客户端,接下来会讲一下TCP模式普通场景下的服务端,说普通场景则是暂时不考虑双向测试的可能,毕竟了解一项东西还是先从简单的情况下入手会快些. 对于服务端,并不是我们认为的直 ...
- 【Android应用开发】EasyDialog 源码解析
示例源码下载 : http://download.csdn.net/detail/han1202012/9115227 EasyDialog 简介 : -- 作用 : 用于在界面进行一些介绍, 说明; ...
- IPerf——网络测试工具介绍与源码解析(1)
IPerf是一个开源的测试网络宽带并能统计并报告延迟抖动.数据包丢失率信息的控制台命令程序,通过参数选项可以方便地看出,通过设置不同的选项值对网络带宽的影响,对于学习网络编程还是有一定的借鉴意义,至少 ...
- Android Handler机制(四)---Handler源码解析
Handler的主要用途有两个:(1).在将来的某个时刻执行消息或一个runnable,(2)把消息发送到消息队列. 主要依靠post(Runnable).postAtTime(Runnable, l ...
- Android Handler机制(二)---MessageQueue源码解析
MessageQueue 1.变量 private final boolean mQuitAllowed;//表示MessageQueue是否允许退出 @SuppressWarnings(" ...
- IPerf——网络测试工具介绍与源码解析(2)
对于IPerf源码解析,我是基于2.0.5版本在Windows下执行的情况进行分析的,提倡开始先通过对源码的简单修改使其能够在本地编译器运行起来,这样可以打印输出一些中间信息,对于理解源码的逻辑,程序 ...
- Android Handler机制(三)----Looper源码解析
一.Looper Looper对象,顾名思义,直译过来就是循环的意思,从MessageQueue中不断取出message. Class used to run a message loop for a ...
- 【转载】Android IntentService使用全面介绍及源码解析
一 IntentService介绍 IntentService定义的三个基本点:是什么?怎么用?如何work? 官方解释如下: //IntentService定义的三个基本点:是什么?怎么用?如何wo ...
随机推荐
- bzoj5252 [2018多省省队联测]林克卡特树
斜率优化树形dp?? 我们先将问题转化成在树上选K+1条互不相交路径,使其权值和最大. 然后我们考虑60分的dp,直接维护每个点子树内选了几条路径,然后该点和0/1/2条路径相连 然后我们会发现最后的 ...
- centos7系统服务管理
systemd是RH7系列操作系统开始启用新的系统和服务管理器.它被设计为与sysv init脚本向后兼容,并提供了一些功能,例如在引导时并行启动系统服务,按需激活守护程序或基于依赖关系的服务控制逻辑 ...
- 【爆料】-《布莱顿大学毕业证书》Brighton一模一样原件
布莱顿大学毕业证[微/Q:2544033233◆WeChat:CC6669834]UC毕业证书/联系人Alice[查看点击百度快照查看][留信网学历认证&博士&硕士&海归&am ...
- 【SAP HANA】新建账户和数据库(2)
开启HANA Studio,进入到User和Role的目录,这两个地方是创建账号和权限的. 新建用户 输入用户名和密码即可. 注意,如果系统里有同名的Catalog(数据库)存在的话,会报错,因为默认 ...
- Windows环境下消息中间件RabbitMq的搭建与应用
前言 消息中间件目前已经在很多大型的项目上得到了运用,我们常见的有 RabbitMq, activitymq,kafka,rocketmq,其中rocketmq是阿里自己在kafka的基础上用java ...
- 深入学习Redis(2):持久化
前言 在上一篇文章中,介绍了Redis的内存模型,从这篇文章开始,将依次介绍Redis高可用相关的知识——持久化.复制(及读写分离).哨兵.以及集群. 本文将先说明上述几种技术分别解决了Redis高可 ...
- 视频当道的时代,这些珍藏的优质 Python 播客值得推荐
我国互联网的发展道路与欧美不同,在内容的形式上,我们似乎实现了跨越式的发展——早早进入了移动互联网时代,直播和短视频等形式的内容成为了潮流,而文字形式的博客(blog)与声音形式的播客(podcast ...
- 补习系列(18)-springboot H2 迷你数据库
目录 关于 H2 一.H2 用作本地数据库 1. 引入依赖: 2. 配置文件 3. 样例数据 二.H2 用于单元测试 1. 依赖包 2. 测试配置 3. 测试代码 小结 关于 H2 H2 数据库是一个 ...
- 基于Vue2-Calendar改进的日历组件(含中文使用说明)
一,前言 我是刚学Vue的菜鸟,在使用过程中需要用到日历控件,由于项目中原来是用jQuery写的,因此用了bootstarp的日历控件,但是配合Vue实在有点蛋疼,不够优雅…… 于是网上搜了好久找到了 ...
- Cesium 海拔 经纬度 展示
通过参考http://gishome.net.cn/cesium/cesium-coordinates/,整理修改后 <!DOCTYPE html><html lang=" ...