目录:
1. 前言
本篇文章是对 Android HandlerThread 类的学习,通过简单的例子,及分析源码来深入学习。同时例子将以 Java & Kotlin 两种代码形式展示。
1.1 定义
HandlerThread: 一个拥有 Looper 对象的线程。
继承于 Thread 类,并拥有一个 Looper 对象,可以利用该 Looper 对象来创建 Handler 对象,就像正常的线程一样,通过调用 start() 方法来开启线程。
1.2 使用场景
适用于子线程多任务的工作场景。如:多个网络请求,多个I/O操作
2. 使用方法
其使用方法很简单:
- 在主线程中新建一个 HandlerThread 对象,然后调用 start() 方法启动该线程。
- 创建一个主线程Handler 对象,关联APP主Looper对象,用于子线程与主线程之间的沟通。
- 创建一个工作线程Handler 对象,关联 HandlerThread 的 Looper 对象。
- 发送消息给工作线程,工作线程Handler 接收消息,并处理消息,然后调用主线程。Handler,发送信息给主线程,通知主线程做UI工作。
- 当对应的 Activity 销毁时,退出 HandlerThread,终止消息循环。
比如:我们用两个 ProgressBar 来模拟在子线程中进行下载任务,点击按钮开始下载,ProgressBar 的进度代表着下载进度。
如下所示:
HandlerThread子线程执行多任务.gif
2.1 Java版本
具体代码如下:
public class HandlerThreadActivity extends AppCompatActivity {
private final int SET_PROGRESS_BAR_1 = 1;
private final int SET_PROGRESS_BAR_2 = 2;
private HandlerThread myHandlerThread;
private Handler mWorkHandler, mMainHandler;
private ProgressBar progressBar1, progressBar2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_handler_thread);
TextView titleTv = findViewById(R.id.title_tv);
titleTv.setText("HandlerThread");
progressBar1 = findViewById(R.id.progress_bar_1);
progressBar2 = findViewById(R.id.progress_bar_2);
Button startBtn1 = findViewById(R.id.start_progress_bar_1_btn);
Button startBtn2 = findViewById(R.id.start_progress_bar_2_btn);
//创建HandlerThread对象
myHandlerThread = new HandlerThread("myHandlerThread");
//启动线程
myHandlerThread.start();
//创建主线程Handler,关联APP的主Looper对象
mMainHandler = new Handler(getMainLooper());
//创建工作线程Handler,关联HandlerThread的Looper对象,所以它无法与主线程通讯
mWorkHandler = new Handler(myHandlerThread.getLooper()) {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case SET_PROGRESS_BAR_1:
//设置Progress Bar 1
for (int i = 1; i <= 4; i++) {
try {
//模拟耗时工作
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
final int progressSchedule = I;
//在工作线程中,通过主线程Handler, 传递信息给主线程,通知主线程处理UI工作。
mMainHandler.post(new Runnable() {
@Override
public void run() {
progressBar1.setProgress(progressSchedule);
}
});
}
break;
case SET_PROGRESS_BAR_2:
//设置Progress Bar 2
for (int i = 1; i <= 4; i++) {
try {
//模拟耗时工作
Thread.sleep(1300);
} catch (InterruptedException e) {
e.printStackTrace();
}
final int progressSchedule2 = I;
//在工作线程中,通过主线程Handler, 传递信息给主线程,通知主线程处理UI工作。
mMainHandler.post(new Runnable() {
@Override
public void run() {
progressBar2.setProgress(progressSchedule2);
}
});
}
break;
default:
break;
}
}
};
startBtn1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//通过工作线程Handler,mWorkHandler发送处理 progress bar 1 的信息给工作线程。
Message msg = new Message();
msg.what = SET_PROGRESS_BAR_1;
mWorkHandler.sendMessage(msg);
}
});
startBtn2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//通过工作线程Handler mWorkHandler发送处理 progress bar 2 的信息给工作线程。
Message msg = new Message();
msg.what = SET_PROGRESS_BAR_2;
mWorkHandler.sendMessage(msg);
}
});
}
@Override
protected void onDestroy() {
super.onDestroy();
myHandlerThread.quit();
}
}
2.2 Kotlin版本
Kotlin 版本代码如下:
class TestHandlerThreadActivity : AppCompatActivity(), View.OnClickListener {
var mHandlerThread: HandlerThread? = null
var mMainHandler: Handler? = null
var mWorkHandler: WorkHandler? = null
override fun onClick(v: View?) {
when (v?.id) {
R.id.handlerThreadStart1Btn -> mWorkHandler?.obtainMessage(1)?.sendToTarget()
R.id.handlerThreadStart2Btn -> mWorkHandler?.obtainMessage(2)?.sendToTarget()
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_test_handler_thread)
mMainHandler = Handler(Looper.getMainLooper())
mHandlerThread = HandlerThread("JereTest")
mHandlerThread!!.start()
mWorkHandler = WorkHandler(mHandlerThread!!.looper)
handlerThreadStart1Btn.setOnClickListener(this)
handlerThreadStart2Btn.setOnClickListener(this)
}
inner class WorkHandler(looper: Looper) : Handler(looper) {
override fun handleMessage(msg: Message) {
super.handleMessage(msg)
when (msg.what) {
1 -> {
for (i in 1..5) {
Thread.sleep(1000)
mMainHandler?.post { handlerThreadProgressBar1.progress = I }
}
}
2 -> {
for (j in 1..5) {
Thread.sleep(1000)
mMainHandler?.post { handlerThreadProgressBar2.progress = j }
}
}
}
}
}
override fun onDestroy() {
super.onDestroy()
mHandlerThread?.quit()
}
}
3. 源码分析
按使用步骤来分析源码:
HandlerThread使用方法步骤一:在主线程中新建一个 HandlerThread 对象,然后调用 start() 方法启动该线程。
//创建 HandlerThread 对象
myHandlerThread = new HandlerThread("myHandlerThread");
//启动线程,执行 run() 方法
myHandlerThread.start();
//创建 HandlerThread 对象,看其构造函数
/**
* HandlerThread的构造函数
* @param name,线程名字是我们传入的,用于标记改线程
*/
public HandlerThread(String name) {
super(name);
//指定该线程的优先级为标准线程优先级
mPriority = Process.THREAD_PRIORITY_DEFAULT;
}
//启动线程
@Override
public void run() {
//获得线程标识符
mTid = Process.myTid();
//为该线程创建一个 Looper 对象,具体见下:
Looper.prepare();
synchronized (this) {
//获取通过 Looper.prepare() 方法创建的 Looper 对象。
mLooper = Looper.myLooper();
//唤醒那些为创建Looper对象而阻塞的线程
notifyAll();
}
//设置该线程的优先级,比如设置为标准线程优先级
Process.setThreadPriority(mPriority);
//消息循环前做的处理,即:如果想在消息循环前做一些处理,则需要复写onLooperPreopared()方法。
onLooperPrepared();
//循环该Looper对象中的消息队列
Looper.loop();
mTid = -1;
}
步骤二:创建一个主线程Handler 对象,关联APP主Looper对象,用于子线程与主线程之间的沟通。
//创建主线程Handler,关联APP的主Looper对象
mMainHandler = new Handler(getMainLooper());
其具体源码分析内容请看另外一篇文章Android Handler 深入学习及源码分析
步骤三. 创建一个工作线程Handler 对象,关联 HandlerThread 的 Looper 对象。
其具体实现方法如下:
//创建工作线程Handler,关联HandlerThread的Looper对象,所以它无法与主线程通讯
mWorkHandler = new Handler(myHandlerThread.getLooper()) {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
···略···
}
};
通过 getLooper() 方法获取 HandlerThread 的 Looper 对象,其源码如下:
/**
* 该方法返回该线程所关联的Looper对象。
* 如果这个线程没有启动,或者由于任何原因isAlive()返回false,那么这个方法将返回null。
* 如果这个线程已经启动,这个方法将阻塞,直到looper被初始化。
* @return The looper.
*/
public Looper getLooper() {
//线程未激活,返回 null
if (!isAlive()) {
return null;
}
//如果该线程已经启动,则阻塞该方法,直到创建好Looper对象。
synchronized (this) {
while (isAlive() && mLooper == null) {
try {
wait();
} catch (InterruptedException e) {
}
}
}
return mLooper;
}
步骤四:发送消息给工作线程,工作线程Handler 接收消息,并处理消息,然后调用主线程Handler,发送信息给主线程,通知主线程做UI工作。
Handler 通过 sendMessage(Msg) 及 post(Runnable) 方法传递消息,本篇博客不展开具体分析,具体源代码分析见上一篇博客Android Handler 深入学习及源码分析
步骤五:当对应的 Activity 销毁时,退出 HandlerThread,终止消息循环。
当当前 Activity 退出销毁时,复写 onDestry() 方法,退出 HandlerThread,如:
@Override
protected void onDestroy() {
super.onDestroy();
myHandlerThread.quit();
}
通过 quit() 方法退出 HandlerThread,终止消息循环,具体源代码分析,见下:
/**
* 终止 Handler 关联的 looper 消息循环,不在处理消息队列中的任何消息。
* 当 looper 被停止后再尝试请求消息入消息队列,会失败,比如:sendMessage(Message) 会返回 false。
* 使用该方法可能不安全,因为 looper 在没有循环分发完所有消息时就被停止了。
* 考虑使用quitsafe() 方法来代替,以确保所有未完成的工作以有序的方式完成。
*
* @return 如果Looper停止消息循环,返回True; 如果线程尚未开始运行,则返回false。
*/
public boolean quit() {
//获取 Handler 所关联的 Looper 对象。
Looper looper = getLooper();
//如果 Looper 不为空,停止其消息循环,返回true
if (looper != null) {
looper.quit();
return true;
}
//如果 Looper 为空,即现场还未开始运行,返回 false。
return false;
}
/**
* 安全的终止 Handler 关联的 Looper 消息循环,处理消息队列中所有已到期的消息,而未到期的挂起的延迟消息将不被传递
* 处理完消息队列中的所有消息后立即停止 Looper 消息循环
* 当 looper 被停止后再尝试请求消息入消息队列,会失败,比如:sendMessage(Message) 会返回 false。
* 如果线程还未开始或已经结束(getLooper 返回 null),返回false;另外,当 Looper 被要求 quit() 停止消息循环时,返回true。
*
* @return 如果Looper停止消息循环,返回True; 如果线程尚未开始运行,则返回false。
*/
public boolean quitSafely() {
Looper looper = getLooper();
if (looper != null) {
//
looper.quitSafely();
return true;
}
return false;
}
至此 HandlerThread 的源码也就分析结束了。
其实分享文章的最大目的正是等待着有人指出我的错误,如果你发现哪里有错误,请毫无保留的指出即可,虚心请教。
另外,如果你觉得文章不错,对你有所帮助,请给我点个赞,就当鼓励,谢谢~Peace~!
网友评论