前言
在读这篇文章之前最好先读一下我之前写的关于Handler原理的文章:Android Handler消息源码分析,这样会比较容易理解handlerThread的原理。
内容
HandlerThread相信很多人都已经用过,还不了解或者没有用过的同学请自行搜索。
先贴一下sample code
HandlerThread handlerThread = new HandlerThread("sample");
handlerThread.start();
Handler handler = new Handler(handlerThread.getLooper(), new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
Log.v("test","handleMessage");
return false;
}
});
for(int i=0;i<10;i++){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
handler.sendMessage(Message.obtain());
}
废话不多讲,直接看HandlerThread的构造方法
public HandlerThread(String name) {
super(name);
mPriority = Process.THREAD_PRIORITY_DEFAULT;
}
因为HandlerThread类是继承自Thread类,所以先调用父类的方法,将Thread Name赋值,接着设置线程优先级。
接着在sample code中会调用start()
方法,我们知道这个会让线程开始运行,并调用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对象,并给mLooper
赋值。我们知道Looper.prepare()
方法在哪个线程调用,这个Looper就属于哪个线程,所以在这里这个Looper就属于HandlerThread这个子线程。接着加一个锁,给mLooper
赋值,然后通知等待线程。这段代码是对应于后面的另一个getLooper()
方法,然后调用onLooperPrepared()
,这个是空方法,子类在继承HandlerThread的时候可以重写这个方法,这样可以在消息循环真正跑起来之前做一些准备工作,然后再调用Looper.loop(),让消息循环真正跑起来。
我们继续看sample code,
Handler handler = new Handler(handlerThread.getLooper(), new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
Log.v("test","handleMessage");
return false;
}
});
就是初始化一个Handler对象,将handlerThread的Looper作为参数专递给handler,这样做的作用是handler之后发送的消息就会送到这个handlerThread的子线程,而不是我们通常在使用的MainThread即UI线程。我们这里重点看一下handlerThread.getLooper()
方法。
/**
* This method returns the Looper associated with this thread. If this thread not been started
* or for any reason 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()) {
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;
}
从方法注释我们知道,只有当线程是live状态的时候才可以返回值,否则就返回null,这里面也有一个锁,大致逻辑就是如果发现mLoope
r是null
则等待,直到被唤醒,那谁会唤醒它呢?从前面的分析知道,这个mLooper
是在run
方法里被赋值,也是在run方法里被赋值后唤醒getLooper
方法中的锁,这个就实现了只要调用getLooper
方法,就可以获得子线程looper的目的。
接下来就是用handler调用SendMessage给handlerThread发送消息了,这个中间的原理在之前的:Android Handler消息源码分析已经讲过,这里不再重复。最后调用handlerThread.quitSafely()
方法退出HandlerThread的消息循环
public boolean quitSafely() {
Looper looper = getLooper();
if (looper != null) {
looper.quitSafely();
return true;
}
return false;
}
逻辑就是安全的退出消息循环,然后从run()
方法返回,线程结束。handler还有另外一个退出方法就是quit()
,这两个方法的区别是,quitSafely()
在退出线程之前会分发完消息队列中剩下的message
,但有个例外,就是通过postDelay
方法发送的延迟消息也不会被分发,,而quit
是直接退出,不管消息队列中还有没有消息,至于选择哪个方法,就看具体使用场景了。好了,就讲到这里,是不是很简单。