Android多线程之 HandlerThread 源码分析
文章目录
一、前言
这主要是一个讲解 Android 中多线程的系列,全部文章如下:
- Android 多线程之 Handler 基本使用
- Android 多线程之 Handler 源码分析
- Android 多线程之 HandlerThread源码分析
- Android 多线程之 AsyncTask使用源码分析
- Android 多线程之 IntentService使用源码分析
前面写了 Android 中的消息机制,也就是 Handler 的消息机制。不了解的可以去看下 Handler系列—源码分析。
本章就来使用和分析下 HandlerThread。
二、什么是 HandlerThread?
我们看下官方的描述:

可以看到 HandlerThread 是继承于 Thread 类的,说明我们可以使用它开启一个子进程去执行一些操作。
再看下官方说明:
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可以去创建一个Handler,但是还是必须得调用start()方法。
我们大概知道 HandlerThread 更加方便了我们在 Android 中进行多线程消息传递。
下面我们通过实例了解下:
public class HandlerThreadTestActivity extends AppCompatActivity {
private static final String TAG = "HandlerThreadTest";
private TextView mShow;
private HandlerThread mHandlerThread = new HandlerThread("MyHandlerThread");
private Handler mHandler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_handler_thread_test);
mShow = findViewById(R.id.show);
mHandlerThread.start();
mHandler = new Handler(mHandlerThread.getLooper()) {
@Override
public void handleMessage(Message message) {
super.handleMessage(message);
final int what = message.what;
mShow.setText("得到的 what 为: "+what );
Log.d(TAG, "handleMessage: " + message.what);
}
};
findViewById(R.id.button1).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mHandler.sendMessage(mHandler.obtainMessage(1));
}
});
findViewById(R.id.button2).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mHandler.sendMessage(mHandler.obtainMessage(2));
}
});
findViewById(R.id.button3).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mHandler.sendMessage(mHandler.obtainMessage(3));
}
});
}
}
运行程序,不出意外会得到如下异常:

原因已经很清楚了,我们在子线程中做了更新 UI 的操作。
下面来分析下原因:
由于 HandlerThread 是继承于 Thread 的,所以在实例化的 HandlerThread 对象是一个子线程,我们在创建 Handler 的时候,传入了 mHandlerThread 对象所在的线程的 Looper 对象,一个线程中只能有一个 Looper 对象,进而使 mHandler 和 子线程进行了绑定,所以这个 mHandler 是属于 mHandlerThread 的。
大家都知道只有主线程的 Handler 对象才能够进行更新 UI 的操作,所以在 mHandler 中执行 UI 操作时肯定不行的。
所以我们需要这样写:
runOnUiThread(new Runnable() {
@Override
public void run() {
mShow.setText("得到的 what 为: "+what );
}
});
代码 才能真正的运行。
通过上面的分析,大家应该能够知道 HandlerThread 是什么了。
- 由于继承于
Thread,所以HandlerThread就是一个线程类; HandlerThread内部拥有一个Looper循环,可以直接传递给Handler使用
其实 HandlerThread 就是一个包含了 Looper 的 Thread,可以免去我们在子线程中创建 Handler 的时候写一些多余的代码。
比如我们在上篇文章的 2-1 章节 章节中创建一个子线程中的 Handler :
new Thread(new Runnable() {
@Override
public void run() {
Looper.prepare();
Handler threadHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
}
};
Looper.loop();
}
}).start();
使用了 HandlerThread 以后我们只需要:
private HandlerThread mHandlerThread = new HandlerThread("MyHandlerThread");
mHandlerThread.start();
Handler threadHandler = new Handler(mHandlerThread.getLooper()) {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
}
};
这样看上去是不是清晰了许多?就是省去了创建 Looper 和 开启 loop 的操作
三、HandlerThread 解析
由于这个类的代码很少,我们都看下。
1.成员变量和构造方法
public class HandlerThread extends Thread {
int mPriority;
int mTid = -1;
Looper mLooper;
private @Nullable Handler mHandler;
public HandlerThread(String name) {
super(name);
mPriority = Process.THREAD_PRIORITY_DEFAULT;
}
/**
* Constructs a HandlerThread.
* @param name
* @param priority The priority to run the thread at. The value supplied must be from
* {@link android.os.Process} and not from java.lang.Thread.
*/
public HandlerThread(String name, int priority) {
super(name);
mPriority = priority;
}
}
可以看到,HandlerThread 的成员变量很简单,
mPriority是优先级mTid是线程的标示符,主要和线程的优先级有关mLooper是内部持有的Looper对象mHandler是与之绑定的Handler对象
构造方法也只有两个:
-
第一个构造函数
第一个只需要传入线程的名称就行了,会把线程的优先级设置了默认的 -
第一个构造函数
第二个则根据自己的需要传入线程的名称和优先级,根据注释可以知道,这个优先级必须是从android.os.Process类中获取,不能从Thread类中获取
2、onLooperPrepared 方法
继续往下看,会看到一个空实现的方法
/**
* Call back method that can be explicitly overridden if needed to execute some
* setup before Looper loops.
*/
protected void onLooperPrepared() {
}
根据注释可以知道,这个方法是给我们在创建 Looper 之后,开启 Looper 循环之前的一些操作使用的。
也就是说在 Looper.prepare() 之后 ,在 Looper.loop() 之前需要做的操作,写在这里,上一篇 Handler 源码解析的文章有写到,这里就不多说了。
3、核心 run 方法
由于继承于 Thread,要重写 Thread 的核心方法 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 对象,关于里面的内容,如果看过上篇文章,应该就知道了。
创建完 Looper 以后,通过 Looper 的 Looper.myLooper() 赋值给其成员变量 mLooper。
Process.setThreadPriority(mPriority); 就是设置线程的优先级,
onLooperPrepared(); 就是上面的空方法
Looper.loop(); 开启 Looper 循环,不断的查看 MessageQueue 中有没有新消息
最终执行完以后把 mTid置为 -1。
可能你发现了 notifyAll(); 这个方法,那么是干嘛的呢?其实我在 Java多线程 有讲到:
Object 类中提供了 wait() 方法,导致当前线程等待,直到其他线程调用此对象的 notify() 方法或 notifyAll() 唤醒方法,才会继续执行。
其实这个地方的 notifyAll() 和下面的 getLooper() 代码是有关的。
4. 获取 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;
}
代码中先判断了是线程是否存活,如果不存活,就直接返回 null.
然后我们就看到了的上面提到的 wait() 方法,也就是说如果这个线程没有执行 run() 方法之前,就去调用 getLooper() 是拿不到的。只有执行了 run() 方法了以后,执行了 notifyAll 才会继续解除这里的 wait 等待,才能正确的获取到 mLooper 对象。
5. 其他方法
@NonNull
public Handler getThreadHandler() {
if (mHandler == null) {
mHandler = new Handler(getLooper());
}
return mHandler;
}
getThreadHandler 获取一个和当前线程关联的 Handler 对象
public boolean quit() {
Looper looper = getLooper();
if (looper != null) {
looper.quit();
return true;
}
return false;
}
quit 退出 Handler 线程的循环
public boolean quitSafely() {
Looper looper = getLooper();
if (looper != null) {
looper.quitSafely();
return true;
}
return false;
}
quitSafely 安全的退出 Handler 线程的循环
上面的 quit 和 quitSafely 都调用了 MessageQueue 中的方法:
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);
}
}
-
quit调用了removeAllMessagesLocked();作用是把
MessageQueue消息池中所有的消息全部清空,无论是延迟消息(延迟消息是指通过sendMessageDelayed或通过postDelayed等方法发送的需要延迟执行的消息)还是非延迟消息。 -
quitSafely调用了removeAllFutureMessagesLocked()该方法只会清空
MessageQueue消息池中所有的延迟消息,并将消息池中所有的非延迟消息派发出去让Handler去处理,quitSafely相比于quit方法安全之处在于清空消息之前会派发所有的非延迟消息。
无论调用了 quit 还是 quitSafely,线程中的 Looper 都不会接受新的消息了,消息队列终结,这时候再通过 Handler 调用 sendMessage 或 post 等方法发送消息时均返回 false ,表示消息没有成功放入消息队列 MessageQueue 中,因为消息队列已经退出了。
四、小结
至此 HandlerThread 的源码已经分析完了,相对来说 HandlerThread 就是做了一些封装,理解和用起来都是不难的。
下篇文章看下 AsyncTask。

本文详细解析了Android中的HandlerThread,介绍了其工作原理、如何使用及源码分析,对比了使用HandlerThread与传统方式创建子线程的区别。
1007

被折叠的 条评论
为什么被折叠?



