HandlerThread是什么?
一个自带Handler的Thread?
字面意思上这么理解是没错,但是更确切的讲是一个内含有Looper的Thread,这点从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.
*/
用于启动具有looper的新线程的方便类。 可以使用looper来创建处理程序类。 注意仍然必须调用start()来启动。
要想获取一个与之绑定的Handler可以通过内置的getThreadHandler()方法获得。
public Handler getThreadHandler() {
if (mHandler == null) {
mHandler = new Handler(getLooper());
}
return mHandler;
}
那么,当从调用handlerThread.start()方法那一刻开始,其内部发生了什么呢?Thread的start()方法注释如下。
/**
* Causes this thread to begin execution; the Java Virtual Machine
* calls the run
method of this thread.
*/
导致此线程开始执行; Java虚拟机调用此线程的 run code>方法。
So,去看看HandlerThread的run()方法。
@Override
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
run()方法里没有什么陌生的东西,先是调用了Looper.prepare()方法创建一个Looper,然后加了一个同步锁获取当前线程的Looper对象赋值到mLooper上并唤醒所有线程,再然后设置当前线程优先级,再然后调用了onLooperPrepared()方法,最后调用Looper.loop()开启循环。
可能会有些好奇为什么在赋值mLooper时要加同步锁,后面会有解释。
看到这里,你可能会想,这跟我们自己继承Thread在run方法里开启一个Looper没什么两样吗,的确,但是官方也说了HandlerThread是一个方便类,方便我们在子线程使用Handler。
对了,上面run()方法里的onLooperPrepared()方法是干什么的?
/**
* Call back method that can be explicitly overridden if needed to execute some
* setup before Looper loops.
*/
protected void onLooperPrepared() {
}
如果需要在Looper循环之前执行某些设置,可以复写此方法。
emmm,那run()方法里加同步锁是为什么呢?
如果你不想通过HandlerThread为我们提供的getThreadHandler()方法来获取一个Handler,HandlerThread也提供了getLooper()方法为你提供Looper对象创建实现自己的Handler。
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;
}
这下就明白为啥在run()方法同步锁里赋值mLooper完成后要在再唤醒所有线程了。因为此方法将阻塞线程,直到looper已初始化。
整个HandlerThread类也就不到200行代码,除了上面那些,它还封装了线程不使用时退出Looper的方法。
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真的是一个方便类啊,cao方便啊!
相比于普通的Thread,我为什么要使用HandlerThread?
对于普通的Thread,执行一遍就结束了,一个实例不能start多次,如果你不止一次启动同一个示例,那么将会抛出一个IllegalThreadStateException异常,这些在Thread的源码里都有注释写到。
/**
* It is never legal to start a thread more than once.
* 不止一次启动线程永远不合法
* In particular, a thread may not be restarted once it has completed execution.
* 特别是,一旦完成执行,线程可能无法重新启动。
* @exception IllegalThreadStateException if the thread was already started.
* 如果线程已经启动将抛出IllegalThreadStateException异常
*/
如果我要频繁的操作数据库、大文件、请求网络,我就要频繁的创建Thread示例调用start(),又或是需要执行一系列串行操作;而HandlerThread由于自带Handler,也就相当自带了一个任务队列,需要进行耗时操作的时候只要通过Handler执行send或post系列操作就行,不再需要频繁创建Thread,节省资源。