Android源码分析之HandlerThread
HandlerThread是一种特殊的Thread,也就是有Looper的thread,既然有looper的话,那我们就可以用此looper来
创建一个Handler,从而实现和它的交互,比如你可以通过与它关联的Handler对象在UI线程中发消息给它处理。HandlerThread
一般可以用来执行某些background的操作,比如读写文件(在此HandlerThread而非UI线程中)。既然还是一个Thread,那么
和一般的Thread一样,也要通过调用其start()方法来启动它。它只是Android替我们封装的一个Helper类,其源码相当简洁,我们
下面来看看,很简单。
和以往一样,我们先来看看字段和ctor:
int mPriority; // 线程优先级
int mTid = -1; // 线程id
Looper mLooper; // 与线程关联的Looper public HandlerThread(String name) { // 提供个名字,方便debug
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; // 使用用户提供的优先级,基于linux优先级,取值在[-20,19]之间
}
代码很简单,相关的分析都直接写在代码的注释里了,值得注意的是这里的priority是基于linux的优先级的,而不是Java Thread
类里的MIN_PRIORITY,NORM_PRIORITY,MAX_PRIORITY之类,请注意区分(其实认真阅读方法的doc即可)。
接下来看看此类的关键3个方法:
/**
* Call back method that can be explicitly overridden if needed to execute some
* setup before Looper loops.
*/
protected void onLooperPrepared() { // callback方法,如果你愿意可以Override放自己的逻辑;其在loop开始前执行
} @Override
public void run() {
mTid = Process.myTid();
Looper.prepare(); // 此方法我们前面介绍过,会创建与线程关联的Looper对象
synchronized (this) { // 进入同步块,当mLooper变的可用的使用,调用notifyAll通知其他可能block在当前对象上的线程
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority); // 设置线程优先级
onLooperPrepared(); // 调用回调函数
Looper.loop(); // 开始loop
mTid = -1; // reset为invalid值
} /**
* 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()) { // 如果线程不是在alive状态则直接返回null,有可能是你忘记调start方法了。。。
return null;
} // If the thread has been started, wait until the looper has been created.
synchronized (this) {
while (isAlive() && mLooper == null) { // 进入同步块,当条件不满足时无限等待,
try { // 直到mLooper被设置成有效值了才退出while(当然也可能是线程状态不满足);
wait(); // run方法里的notifyAll就是用来唤醒这里的
} catch (InterruptedException e) { // 忽略InterruptedException
}
}
}
return mLooper; // 最后返回mLooper,此时可以保证是有效值了。
}
当你new一个HandlerThread的对象时记得调用其start()方法,然后你可以接着调用其getLooper()方法来new一个Handler对象,
最后你就可以利用此Handler对象来往HandlerThread发送消息来让它为你干活了。
最后来看2个退出HandlerThread的方法,其实对应的是Looper的2个退出方法:
/**
* Quits the handler thread's looper.
* <p>
* Causes the handler thread's looper to terminate without processing any
* more messages in the message queue.
* </p><p>
* Any attempt to post messages to the queue after the looper is asked to quit will fail.
* For example, the {@link Handler#sendMessage(Message)} method will return false.
* </p><p class="note">
* Using this method may be unsafe because some messages may not be delivered
* before the looper terminates. Consider using {@link #quitSafely} instead to ensure
* that all pending work is completed in an orderly manner.
* </p>
*
* @return True if the looper looper has been asked to quit or false if the
* thread had not yet started running.
*
* @see #quitSafely
*/
public boolean quit() {
Looper looper = getLooper(); // 注意这里是调用getLooper而不是直接使用mLooper,
if (looper != null) { // 因为mLooper可能还没初始化完成,而调用方法可以
looper.quit(); // 等待初始化完成。
return true;
}
return false;
} /**
* Quits the handler thread's looper safely.
* <p>
* Causes the handler thread's looper to terminate as soon as all remaining messages
* in the message queue that are already due to be delivered have been handled.
* Pending delayed messages with due times in the future will not be delivered.
* </p><p>
* Any attempt to post messages to the queue after the looper is asked to quit will fail.
* For example, the {@link Handler#sendMessage(Message)} method will return false.
* </p><p>
* If the thread has not been started or has finished (that is if
* {@link #getLooper} returns null), then false is returned.
* Otherwise the looper is asked to quit and true is returned.
* </p>
*
* @return True if the looper looper has been asked to quit or false if the
* thread had not yet started running.
*/
public boolean quitSafely() {
Looper looper = getLooper();
if (looper != null) {
looper.quitSafely();
return true;
}
return false;
}
通过代码我们可以看到其内部都是delegate给了Looper对象,而Looper我们在前面也介绍过了,感兴趣的同学可以翻看前面的分析或者
查看这2个方法的doc,写的都很详细。
至此这个简单的Handy class就算分析完毕了。在实际的开发中,如果你只是要做某些后台的操作(短暂的,比如把某些设置文件load
到内存中),而不需要更新UI的话,那你可以优先使用HandlerThread而不是AsyncTask。
接下来准备分析下Android提供的数据存储机制SharedPreferences,敬请期待。。。
Android源码分析之HandlerThread的更多相关文章
- Android源码分析-全面理解Context
前言 Context在android中的作用不言而喻,当我们访问当前应用的资源,启动一个新的activity的时候都需要提供Context,而这个Context到底是什么呢,这个问题好像很好回答又好像 ...
- Android源码分析(六)-----蓝牙Bluetooth源码目录分析
一 :Bluetooth 的设置应用 packages\apps\Settings\src\com\android\settings\bluetooth* 蓝牙设置应用及设置参数,蓝牙状态,蓝牙设备等 ...
- Android源码分析(十七)----init.rc文件添加脚本代码
一:init.rc文件修改 开机后运行一次: chmod 777 /system/bin/bt_config.sh service bt_config /system/bin/bt_config.sh ...
- Android源码分析(十六)----adb shell 命令进行OTA升级
一: 进入shell命令界面 adb shell 二:创建目录/cache/recovery mkdir /cache/recovery 如果系统中已有此目录,则会提示已存在. 三: 修改文件夹权限 ...
- Android源码分析(十五)----GPS冷启动实现原理分析
一:原理分析 主要sendExtraCommand方法中传递两个参数, 根据如下源码可以知道第一个参数传递delete_aiding_data,第二个参数传递null即可. @Override pub ...
- Android源码分析(十四)----如何使用SharedPreferencce保存数据
一:SharedPreference如何使用 此文章只是提供一种数据保存的方式, 具体使用场景请根据需求情况自行调整. EditText添加saveData点击事件, 保存数据. diff --git ...
- Android源码分析(十三)----SystemUI下拉状态栏如何添加快捷开关
一:如何添加快捷开关 源码路径:frameworks/base/packages/SystemUI/res/values/config.xml 添加headset快捷开关,参考如下修改. Index: ...
- Android源码分析(十二)-----Android源码中如何自定义TextView实现滚动效果
一:如何自定义TextView实现滚动效果 继承TextView基类 重写构造方法 修改isFocused()方法,获取焦点. /* * Copyright (C) 2015 The Android ...
- Android源码分析(十一)-----Android源码中如何引用aar文件
一:aar文件如何引用 系统Settings中引用bidehelper-1.1.12.aar 文件为例 源码地址:packages/apps/Settings/Android.mk LOCAL_PAT ...
随机推荐
- iOS app开发资料整理
Objective C快速入门: http://blog.csdn.net/totogo2010/article/details/7632384 http://www.cocoachina.com/i ...
- 【HTML】Iframe中的onload事件
当iframe.src重新指定一个url时会重新执行iframe的onload事件 <iframe id="indexFrame" name="index" ...
- DDD:《实现领域驱动》拾贝(待续)
Design is not just what it looks like and feels like. Design is how it works.
- IIS 7完全攻略之日志记录配置(摘自网络)
IIS 7完全攻略之日志记录配置 作者:泉之源 [IT168 专稿]除了 Windows 提供的日志记录功能外,IIS 7.0 还可以提供其他日志记录功能.例如,可以选择日志文件格式并指定要记录的请求 ...
- How can I learn to program?
黑客与画家:硅谷创业之父paul graham关于回答‘How can I learn to program’ How can I learn to program? Find a friend wh ...
- 终极事务处理(XTP,Hekaton)——万能大招?
在SQL Server 2014里,微软引入了终极事务处理(Extreme Transaction Processing),即大家熟知的Hekaton.我在网上围观了一些文档,写这篇文章,希望可以让大 ...
- jquery.idTabs使用方法
idTabs是基于Jquery编写封装的一个插件,主要用于实现选项卡功能,它操作简单,只需到官网:http://www.sunsean.com/idTabs/下载插件JS脚本文件,并引用到网站中即可 ...
- 一起Polyfill系列:让Date识别ISO 8601日期时间格式
一.什么是ISO 8601日期时间格式 ISO 8601是国际标准化组织制定的日期时间表示规范,全称是<数据存储和交换形式·信息交换·日期和时间的表示方法>. 示例: 1. 2014-12 ...
- TinyFox在VS2015上的调试器
这个一个TinyFox在VS2015上的调试工具 : 开源了 https://github.com/maxzhang1985/TinyFoxDEBUG 开发这个工具的初衷,是想更便捷的调试Nancy ...
- [Bootstrap]7天深入Bootstrap(4)CSS组件
Bootstrap框架的三大核心之二:组件. 组件也是最核心的地方,因为绝大部分的网页都必须利用组件才能构建出绚丽的页面. 组件包括:Icon图标(Glyphicon). 下拉菜单(Dropdown) ...