HandlerThread是属于Android异步线程模块的一部分,上一篇是AsyncTask的源码:
Android进阶2:线程和线程池(1)—— AsycTask原理解析
如果你没看过handler消息机制,建议先学习下handler消息机制:
Android进阶1:Android的消息机制
记得之前刚接触android的之后,只知道HandlerThread内部原理:Handler + Thread, 始终没看过源码,最近学习到了android线程和线程池模块,自然而然的HandlerThread源码是必须看的。
老规矩,得先会使用HandlerThread再说别的。
需求:使用HandlerThread开启一个子任务,在子任务中,发送消息,在UI主线程接收消息,并显示在TextView上。
public class MainActivity extends AppCompatActivity {
private Handler mainHandler = new Handler() { //主线程的handler
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
String description = msg.getData().getString("description");
textView.setText(description);
}
};
private TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = findViewById(R.id.image_view);
HandlerThread handlerThread = new HandlerThread("test-handler-thread");
handlerThread.start();
Handler childHandler = new Handler(handlerThread.getLooper()) {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
//运行在子线程
String description = msg.getData().getString("description");
Message message = mainHandler.obtainMessage();
Bundle data = message.getData();
data.putString("description", description);
mainHandler.sendMessage(message); //通过主线程的handler发送消息
}
};
for (int i = 0; i < 10; i++) { //子线程childHandler 发送消息
Message message = childHandler.obtainMessage();
Bundle data = new Bundle();
data.putString("description","hello world " + i);
message.setData(data);
childHandler.sendMessageDelayed(message, 1000 * i);
}
}
}
通过上述demo是对handleThread的简单使用,并且我们得到的信息是:
1:HandlerThread成员变量
/**
Handy class for starting a new thread that has a looper. The looper can then be
used to create handler classes. Note that start() must still be called.
*/
//注意点
public class HandlerThread extends Thread {
int mPriority; //线程任务优先级
int mTid = -1;
//注意点
Looper mLooper; //当前线程的Looper对象
private @Nullable Handler mHandler; //传递的handler
......
}
两个注意点:
成员变量含有Looper和Handler对象,也就是处理消息啦。
再看下Google给出的方法描述:创建一个含有Looper的子线程,该Looper用来创建一个Handler对象。无论如何都必须通过start开启。
通过Google的描述,我们使用的HandlerThread的步骤是不是清晰了?
接着往下看,构造函数:
/**
* @param name the name of the new thread
* 线程名称
*/
public HandlerThread(String name) {
super(name);
mPriority = Process.THREAD_PRIORITY_DEFAULT;
}
public HandlerThread(String name, int priority) {
super(name);
mPriority = priority;
}
HandlerThread只有两个构造函数,我们的demo使用的是第一种创建方式,name参数表示线程的名字;
对象创建好了该运行了,那么就得看下start源码了
通过查找,并没有在HandlerThread的源码内找到start()的复写,也就是说执行的是Thread的start方法。再想一下,start()方法调用之后,run()方法就调用了,来看下run()的源码:
@Override
public void run() {
//此时就运行在子线程了!
mTid = Process.myTid();
Looper.prepare(); // 创建子线程的Looper
synchronized (this) {
mLooper = Looper.myLooper(); //获取子线程的Looper
notifyAll(); //注意点1:唤醒所有等待
}
Process.setThreadPriority(mPriority); //设置线程优先级
onLooperPrepared(); //注意点2:looper准备工作
Looper.loop(); //开启Looper调度
mTid = -1;
}
通过上述代码可以看出,run方法主要做的工作就是:创建Looper,并且开启Looper的消息循环。有两个注意点:
注意点2:onLooperPrepared()方法,HandlerThread暴露这个方法,我们的知晓,我们可以在消息Looper开始消息调度前,复写此方法多一些事情。
再回过头看demo创建子线程的handler,看到了handlerThread.getLooper(), 看下源码:
public Looper getLooper() {
if (!isAlive()) { //线程是否存活
return null;
}
// If the thread has been started, wait until the looper has been created.
//如果改线程已经存活,就等到Looper创建好。
synchronized (this) {
while (isAlive() && mLooper == null) { //死循环,等待创建好Looper对象
try {
wait(); //等待唤醒
} catch (InterruptedException e) {
}
}
}
return mLooper; //返回Looper对象
}
此方法返回的是Looper对象,然后先判断线程是否存活,然后判断mLooper是否为null , 如果looper是null,就休眠等待唤醒,休眠? 那什么时候唤醒呢? 还记得run()方法里面的唤醒等待吧? 就是线程间Looper,然后唤醒等待,确保创建使用Handler之前必须有Looper。由于该Looper对象创建在子线程中,所有通过该Looper为参数创建的Handler内部的handlerMessage也是运行在子线程中。可以这样理解:上述demo,发送消息是在主线程,但是执行消息是在子线程,刚好跟我们常用的handler相反。
退出有两种方式:
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;
}
这两种退出方式是不是很熟悉? 没错,就是Looper的两种退出方式,内部调用的是MessageQueue的退出。
至此流程走完了,梳理一下:
创建HandleThread —> start启动 —> 在run方法内创建Looper对象,并唤醒等待 —> 通过run创建的Looper对象,创建一个运行在子线程的handler对象 —> 在子线程的handleMessage方法内,处理消息。
HandlerThread和普通Thread的区别:
Thread: run()中执行耗时操作,执行一次之后就结束,
HandlerThread:run()方法是无限循环的,阻塞等待,通过子线程为参数创建的Handler发送消息,执行任务。因此在明确不需要HandlerThread时,要通过quit或者quitSafely终止线程的执行。
通过上述分析,可以确定的是,HandlerThread原理实际上就是handler + Thread的封装使用
本文感谢《Android开发艺术探索》
如果发现错误,欢迎指正,以便纠正,谢谢哈 = - =