实例分析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 还是比较简单理解的,好了,本篇到此为止,希望对你有帮助。
- Apache Sqoop 将mysql导入到Hadoop HDFS
- Redis 4.0.0 一键安装脚本,CentOS 7 systemd 完美启动
- Spring boot with Apache Hive
- Apache Hive 快速入门
- CentOS 7.3 + Server JRE 1.8 + Hadoop-2.8.0
- Apache Hbase 快速入门
- Mototrbo TMS 协议分析(数字电台短信协议分析)
- Nginx 反向代理可以缓存 HTTP POST 请求页面吗?
- Spring boot with Hive
- Spring data 如何定义默认时间与日期
- Spring boot with Oauth2
- Elasticsearch Cluster 安装与配置
- 数据库结构版本控制
- 【Golang语言社区】LollipopGo框架之商城项目--路由设置
- java教程
- Java快速入门
- Java 开发环境配置
- Java基本语法
- Java 对象和类
- Java 基本数据类型
- Java 变量类型
- Java 修饰符
- Java 运算符
- Java 循环结构
- Java 分支结构
- Java Number类
- Java Character类
- Java String类
- Java StringBuffer和StringBuilder类
- Java 数组
- Java 日期时间
- Java 正则表达式
- Java 方法
- Java 流(Stream)、文件(File)和IO
- Java 异常处理
- Java 继承
- Java 重写(Override)与重载(Overload)
- Java 多态
- Java 抽象类
- Java 封装
- Java 接口
- Java 包(package)
- Java 数据结构
- Java 集合框架
- Java 泛型
- Java 序列化
- Java 网络编程
- Java 发送邮件
- Java 多线程编程
- Java Applet基础
- Java 文档注释
- django filter过滤器实现显示某个类型指定字段不同值方式
- PHP中使用mpdf 导出PDF文件的实现方法
- PyTorch实现重写/改写Dataset并载入Dataloader
- 详细分析Python垃圾回收机制
- PHP实现用session来实现记录用户登陆信息
- django序列化时使用外键的真实值操作
- 网站被恶意镜像怎么办 php一段代码轻松搞定(全面版)
- 如何基于Python爬取隐秘的角落评论
- PHP微信网页授权的配置文件操作分析
- php微信公众号开发之关键词回复
- Python 抓取数据存储到Redis中的操作
- PHP常见字符串操作函数与用法总结
- 利用python对excel中一列的时间数据更改格式操作
- Python 私有属性和私有方法应用场景分析
- django 模型字段设置默认值代码