一、HandlerThread的作用
HandlerThread是 Android 中一种特殊的线程类,它内部封装了 Looper和消息队列,适用于需要后台线程处理消息的场景。在我使用中主要用于在后台线程处理视频相关事件。
为什么要这样用?
-
避免阻塞主线程:视频事件处理(如解码、渲染、网络请求等)通常是耗时操作。直接在 UI 线程处理会导致界面卡顿甚至 ANR。
-
创建专用事件队列:通过
HandlerThread创建了一个具备消息队列的后台线程,所有视频事件可以按顺序处理。 -
线程安全的事件分发:使用
Handler机制保证事件在不同线程间安全传递。
二、HandlerThread源码使用理解
我从源码角度看,首先HandlerThread继承自 Thread,其生命周期的核心在 run()方法中。
当线程通过 start()方法启动后,run()方法会依次执行:调用 Looper.prepare()为当前线程创建唯一的 Looper和 MessageQueue;
@Override
public void run() {
mTid = Process.myTid(); // 获取当前线程ID
Looper.prepare(); // 创建当前线程的Looper和MessageQueue
synchronized (this) {
mLooper = Looper.myLooper(); // 获取当前线程的Looper
notifyAll(); // 唤醒可能阻塞在getLooper()的线程
}
Process.setThreadPriority(mPriority); // 设置线程优先级
onLooperPrepared(); // 回调钩子方法(子类可重写)
Looper.loop(); // 启动消息循环(阻塞在此处)
mTid = -1; // 消息循环退出后重置线程ID
}
通过同步代码块和 notifyAll()机制安全地将创建好的 Looper暴露给外界(例如 UI 线程),这确保了在 getLooper()方法中可能等待的调用方能够及时获得初始化的 Looper;
public Looper getLooper() {
if (!isAlive()) return null; // 线程未启动返回null
synchronized (this) {
while (isAlive() && mLooper == null) {
try {
wait(); // 等待run()中的notifyAll()
} catch (InterruptedException e) {
}
}
}
return mLooper; // 返回已初始化的Looper
}
随后调用 onLooperPrepared()这个钩子方法供子类进行自定义初始化;最后进入 Looper.loop()无限循环,开始从消息队列中取出并处理消息,线程在此处进入阻塞状态,直到收到退出指令。
HandlerThread提供了 quit()和更安全的 quitSafely()方法来终止消息循环,这是防止线程泄漏的关键步骤。
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 是 Android 中一种封装了 Looper 和消息循环的特殊线程,它通过在线程启动时自动创建消息队列并进入阻塞式循环,为后台任务处理提供了基于 Handler 的消息驱动机制,既简化了后台线程的管理复杂度,又实现了线程复用和顺序任务处理,特别适用于视频处理等需要长时间运行的后台场景,使用时需要注意在适当时机调用 quit 方法防止内存泄漏。
4331

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



