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 ...
随机推荐
- loj6271「长乐集训 2017 Day10」生成树求和 加强版
又是一个矩阵树套多项式的好题. 这里我们可以对每一位单独做矩阵树,但是矩阵树求的是边权积的和,而这里我们是要求加法,于是我们i将加法转化为多项式的乘法,其实这里相当于一个生成函数?之后如果我们暴力做的 ...
- bzoj 3239 poj 2417 BSGS
BSGS算法,预处理出ϕ(c)−−−−√内的a的幂,每次再一块一块的往上找,转移时将b乘上逆元,哈希表里O(1)查询即可 #include<cstdio> #include<cstr ...
- 【强连通分量+spfa】Bzoj1179 Apio2009 Atm
Description Solution 显然缩强连通分量,然后求最长路,虽然是DAG但还是有点麻烦,于是用了spfa. Code 重建图_数组写错好多次,感觉做这题也就是练了一下实现. #inclu ...
- BZOJ_3110_[Zjoi2013]K大数查询_整体二分+树状数组
BZOJ_3110_[Zjoi2013]K大数查询_整体二分+树状数组 Description 有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位 ...
- B20J_2733_[HNOI2012]永无乡_权值线段树合并
B20J_2733_[HNOI2012]永无乡_权值线段树合并 Description:n座岛,编号从1到n,每座岛都有自己的独一无二的重要度,按照重要度可以将这n座岛排名,名次用1到 n来表示.某些 ...
- BZOJ_1212_[HNOI2004]L语言_哈希
BZOJ_1212_[HNOI2004]L语言_哈希 Description 标点符号的出现晚于文字的出现,所以以前的语言都是没有标点的.现在你要处理的就是一段没有标点的文章. 一段文章T是由若干小写 ...
- 种树 BZOJ2151 模拟费用流
分析: 我们如果选择点i,那么我们不能选择i-1和i+1,如果没有这个限制,直接贪心就可行,而加上这个限制,我们考虑同样贪心,每次选择i后,将点i-1,i+1从双向链表中删除,并且将-a[i]+a[i ...
- 线性表概述及单链表的Java实现
一.线性表概述 线性表是指一组数据元素之间具有线性关系的元素序列,它表现为:除第一个元素没有直接前驱元素.最后一个元素没有直接后继元素外,其余所有元素都有且仅有一个直接前驱元素和直接后继元素. 根据存 ...
- ssm上传图片
ssm上传图片 1 需求 添加客户时上传图片和客户修改信息是上传图片. 2 思路 首先,数据库创建pic字段,类型为varchar,通过逆向工程重新生成mapper接口和xml文件 ...
- javascript-发布订阅模式与观察者模式
设计模式"(Design Pattern)是针对编程中经常出现的.具有共性的问题,所提出的解决方法.著名的<设计模式>一书一共提出了23种模式. 发布订阅模式 它定义了一种对象间 ...