假设我们从没接触过HandlerThread,单从Handler和Thread这两个词我们大概能猜得出这个类是Handler+Thread。没错这个类就是一个具备消息机制的线程类。
为什么需要这个类
相信大家在刚开始学习Handler的时候都会被告知不能在子线程中直接创建Handler对象,例如如果你运行如下代码程序就会直接奔溃,然后能看到一条错误日志:Can't create handler inside thread Thread[Thread-2,5,main] that has not called Looper.prepare()。
new Thread() {
@Override
public void run() {
super.run();
Handler handler = new Handler();
}
}.start();
从这个错误日志我们就能知道需要在创建Handler对象之前调用下Looper.prepare(),当然要让子线程的消息机制能正常工作还需要再调用下Looper.loop()。而HandlerThread主要就是帮我们把这些事情给做了,让我们可以无需手动设置Looper就能使用Handler。
功能
既然HandlerThread已经帮我们初始化好了Looper,那我们就可以在创建HandlerThread之后创建Handler对象,通过该对象发送消息,然后在子线程处理耗时操作。例如
HandlerThread handlerThread = new HandlerThread("test");
handlerThread.start();
Handler threadHandler = new Handler(handlerThread.getLooper()) {
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case 1:
//做一些耗时操作
break;
}
}
};
threadHandler.sendEmptyMessage(1);
源码解析
聊完了HandlerThread的背景和功能,那我们就深入源码来看看具体是怎么实现的,是不是只加了Looper.preare()和Looper.loop()这两行代码。 首先HandlerThread是一个Thread,所以自然而要做的事情就是继承Thread然后实现最核心的run()方法。
构造函数
就两个构造函数,参数就是设置线程名和线程的优先级,其他没什么好说的。
public HandlerThread(String name) {
super(name);
mPriority = Process.THREAD_PRIORITY_DEFAULT;
}
public HandlerThread(String name, int priority) {
super(name);
mPriority = priority;
}
run()方法
接着我们就要看最核心的方法run();
@Override
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
看这个源码是不是很熟悉,我们看到了Looper.prepare()和Looper.loop()两个最关键的代码。如果不考虑其他问题,其实这两行代码就足够了。那么疑问来了,中间的synchronsized代码块和onLooperPrepared()代码是在干啥用的?
上面在讲使用HandlerThread时,我们在创建Handler时调用了HandlerThread.getLooper()方法,这个函数的功能就是返回子线程的Looper对象,但子线程的Looper是在run()方法中初始化的,那就存在一个情况是HandlerThread使用者创建了一个HandlerThread对象但还没启动线程也就是没调用start()方法之前就去调用了getLooper。如果不做处理的话那么使用者将得到一个null对象。自然,就得在getLooper()中做些处理。查看源码可以看到如果还未初始化Looper对象就会挂起线程直到Looper初始化完成。这样在run()方法中初始化完成之后就会被唤醒。
public Looper getLooper() {
.......省略一些判断.......
synchronized (this) {
while (isAlive() && mLooper == null) {
try {
wait();
} catch (InterruptedException e) {
}
}
}
return mLooper;
}
而onLooperPrepared()方法就是一个空方法,看注释可以直到就在一个在Looper初始化完成后的一个回调,我们可以在继承HandlerThread类时去实现这个方法,比如创建一个Handler对象。
/**
* Call back method that can be explicitly overridden if needed to execute some
* setup before Looper loops.
*/
protected void onLooperPrepared() {
}
其他方法
分析完核心方法之后,我们看到还有一些方法:
- getThreadHandler,获取一个和当前线程的共享Handler对象
public Handler getThreadHandler() {
if (mHandler == null) {
mHandler = new Handler(getLooper());
}
return mHandler;
}
- quit()和quitSafely(),这两个方法的区别就在looper.quit()和looper.quitSafely()。这两个方法的区别是quit会马上结束消息处理功能,不管此刻还有没有消息没处理,而quitSafely会相对温和一点,它依然会此刻需要处理的消息,但不会再处理那些延迟消息,比如通过postDelayed发送的消息。
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;
}
总结
HandlerThread在run方法中初始化Looper,然后对一些异常情况做了一些处理,至于功能,用HandlerThread类中的注释来总结就是:
- 有Looper的Thread;
- 可以用这个Looper去创建Handler对象;
- 像普通Thread一样,记得调用start()方法;