关于HandlerThread你应该知道的一切

什么是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.

从它的名字 HandlerThread 说明它本质上还是一个Thread,只不过前面加了一个定语Handler。可以猜测这个Thread里包含了一个Handler,有Handler肯定还少不了Looper

在Android中,主线程会自动启动一个Looper去不断的处理消息,启动的代码在 ActivityThreadmain方法中代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

public static void main(String[] args) {

...
Looper.prepareMainLooper();
...

ActivityThread thread = new ActivityThread();
thread.attach(false, startSeq);

if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}

if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}

Looper.loop();
...
}

这样系统处理一些消息就可以通过Handler发送消息到Looper的消息队列。如果我们也想有这样的一个消息处理系统怎么办呢,答案就是用HandlerThread

先来看一下HandlerThread的关键代码

run()
1
2
3
4
5
6
7
8
9
10
11
12
13
@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() 和主线程启动类似。在Looper.loop()方法中执行了一个for循环,不断从消息队列(MessageQueue)中取出消息处理。

quit()
1
2
3
4
5
6
7
8
public boolean quit() {
Looper looper = getLooper();
if (looper != null) {
looper.quit();
return true;
}
return false;
}
quitSafely()
1
2
3
4
5
6
7
8
public boolean quitSafely() {
Looper looper = getLooper();
if (looper != null) {
looper.quitSafely();
return true;
}
return false;
}

有两个quit方法,这两个quit方法有什么区别呢?直接看下代码(Looper.java)

1
2
3
4
5
6
7
public void quit() {
mQueue.quit(false);
}

public void quitSafely() {
mQueue.quit(true);
}

最终调用的都是mQueue.quit方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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);
}
}

可以看到,当直接退出的时候,会把消息队列中所有的消息都取消掉。如果是安全退出,会把延时的消息取消掉,非延时的消息会处理完。有点类似线程池ExecutorServiceshutdown()shutdownNow()方法。

Looper 的 quitSafely 方法从 api level 18才可以使用

优点

HandlerThread相比于Thread一次创建线程,就可以不断的处理消息,减少了频繁创建线程带来的资源消耗。

使用场景

满足以下两个场景即可使用HandlerThread

  • 需要子线程处理任务
  • 要处理多个任务

使用

一个小demo