前面已经说过,每一个线程的ThreadLocal都保存了一个looper对象,这个looper对象只存在于安卓之中,通过这个looper,会不断地从消息队列中进行轮训,当有消息到达的时候,就会取出消息,进行处理。
构造函数
Handler正是结合了线程Thread以及Handler,大体上定义了一个线程,并且在启动线程时创建Looper,我们先来看看它的构造函数
//线程优先级默认为Process.THREAD_PRIORITY_DEFAULT
public HandlerThread(String name)
//自定义线程的名字和优先级
public HandlerThread(String name, int priority)
优先级这个值必须是android.os.Process
,不能使用java.lang.Thread
的值,至于为什么,我们会在学习线程,并发编程的时候介绍到。
初始化线程以后,我们来看一下这个线程的run方法
@Override
public void run() {
//获取当前线程的线程id
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
//因为如果Looper还没创建好,有线程想要访问,那么该线程就会进行等待wait,直到这里当looper准备好以后,唤醒所有等待的线程
notifyAll();
}
//设置线程优先级
Process.setThreadPriority(mPriority);
//空方法,重写用于在执行loop之前的一些操作
onLooperPrepared();
Looper.loop();
//退出loop后,把线程id设为-1
mTid = -1;
}
当我们在其他线程,获取这个线程对象的Looper的时候,调用getLooper对象
public Looper getLooper() {
if (!isAlive()) {
return null;
}
// 如果线程已经开启,如果Looper已经创建,往下执行, 否则等待
synchronized (this) {
while (isAlive() && mLooper == null) {
try {
wait();
} catch (InterruptedException e) {
}
}
}
return mLooper;
}
HandlerThread的特殊之处就是loop会无限循环,当消息队列没有消息的时候,阻塞在那里,如果我们不主动关闭looper,跳出loop方法,那么这个线程将一直运行,直到系统把它杀死,当退出关闭线程之前,需要主动停止looper,让线程能够顺利跳出loop方法,然后线程执行完毕,关闭线程。调用下面两个方法跳出loop方法
主动退出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;
}
这两个方法大致上是一样的,分别调用的是Looper里面的两个处理消息队列的方法,在Looper里面实际上调用的是消息队列里面的quit方法
void quit(boolean safe) {
if (!mQuitAllowed) {
throw new IllegalStateException("Main thread not allowed to quit.");
}
synchronized (this) {
if (mQuitting) {
return;
}
mQuitting = true;
if (safe) {
//把消息队列里面还没执行的消息执行完,然后进行回收
removeAllFutureMessagesLocked();
} else {
//直接回收所有的消息
removeAllMessagesLocked();
}
// We can assume mPtr != 0 because mQuitting was previously false.
nativeWake(mPtr);
}
}
虽然这是一个HandlerThread类,但是我们并没有源码中看到Handler的影子。熟知Handler的大佬们都知道,Handler其实只负责发送Message和处理Message,而轮训消息队列的Looper由始至终都和关联的Thread进行绑定,所以我们可以使用这个Thread提供的Looper自定义多个Handler,这些Handler发送的消息都会统一加入到Looper的消息队列中。
HandlerThread的常用用法
public class HandlerThreadActivity extends AppCompatActivity {
private HandlerThread thread;
private MyHandler handler;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
thread = new HandlerThread("sub");
thread.start();
// 使用HandlerThread对象来获取Looper
handler = new MyHandler(thread.getLooper());
}
class MyHandler extends Handler{
MyHandler(Looper looper){
super(looper);
}
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
}
}
@Override
protected void onDestroy() {
super.onDestroy();
// 退出的时候应该关闭Looper
thread.quitSafely();
}
}
当handler发送消息的时候,就能够在异步处理该消息了。