对HandlerThread的一些总结。
概述
HandlerThread
提供了一种能在子线程进行异步操作的消息处理机制,本质上它封装Thread
和Looper
来在子线程进行消息的存储和分发。
涉及到Handler
的相关知识Handler 原理知识点回顾 。
使用
简单的例子:
HandlerThread handlerThread = new HandlerThread("handlerThread"){
@Override
protected void onLooperPrepared() {
super.onLooperPrepared();
Log.d("执行","准备工作");
}
};
handlerThread.start();
//必须在调用handlerThread.start()之后才能创建Handler
final Handler handler = new Handler(handlerThread.getLooper()){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Log.d("消息","在 "+Thread.currentThread().getName()+" 线程,收到 "+msg.obj);
}
};
handler.sendMessage(Message.obtain(handler,1,"test1"));
控制台输出:
08-02 13:57:43.023 27006-27026/com.franky.test D/执行: 准备工作
08-02 13:57:43.023 27006-27026/com.franky.test D/消息: 在 handlerThread 线程,收到 test1
在合适的地方调用退出操作:
handlerThread.quit();
//handlerThread.quitSafely(); API 18才支持此方法
使用相对比较简单,总结如下:
- 创建
HandlerThread
对象,可以重写onLooperPrepared()
方法做一些初始化操作; - 调用
handlerThread.start()
方法; - 创建
Handler
,在构造中传入handlerThread.getLooper()
方法创建的Looper
对象,重写handleMessage(Message msg)
方法,在子线程处理消息; - 使用
Handler
对象在相关场景发送处理消息; 适时退出异步操作
原理
本身
HandlerThread
的源码比较少,直接贴出:
//本身继承了Thread类
public class HandlerThread extends Thread {
int mPriority;//线程优先级
int mTid = -1;//线程id
Looper mLooper;//Looper对象
private @Nullable Handler mHandler;//无法调用
//name为线程的名字
public HandlerThread(String name) {
super(name);
//线程的优先级,这是默认级别,其他的级别在Process中有存储
mPriority = Process.THREAD_PRIORITY_DEFAULT;
}
//可以传入优先级的构造,优先级来自android.os.Process类中
public HandlerThread(String name, int priority) {
super(name);
mPriority = priority;
}
//可以重写此方法做准备工作
protected void onLooperPrepared() {
}
//在调用HandlerThread.start()方法后,run方法会运行
//这里主要是进行了Looper对象的创建和初始化
@Override
public void run() {
mTid = Process.myTid();//获取线程id
Looper.prepare();//准备当前线程的Looper,使用了ThreadLocal存储
synchronized (this) {//进入同步代码块
mLooper = Looper.myLooper();//获取当前线程Looper
notifyAll();//通知线程
}
Process.setThreadPriority(mPriority);//设置线程优先级
onLooperPrepared();//调用准备方法
Looper.loop();//开启消息循环
mTid = -1;//重置线程ID
}
//主要用于获取当前线程关联的Looper对象,用于创建Handler使用
public Looper getLooper() {
//如果线程没有存活,直接返回Null
if (!isAlive()) {
return null;
}
//进入同步代码
synchronized (this) {
//如果线程存活,但是Looper对象还没初始化成功的时候,wait,等待Looper初始化完毕后唤醒
while (isAlive() && mLooper == null) {
try {
wait();
} catch (InterruptedException e) {
}
}
}
return mLooper;
}
//此方法标记为@hide,外部无法直接调用
/**
* @return a shared {@link Handler} associated with this thread
* @hide
*/
@NonNull
public Handler getThreadHandler() {
if (mHandler == null) {
mHandler = new Handler(getLooper());
}
return mHandler;
}
//调用该方法,Looper对象中的MessageQueue存储的Messag,将全部被情况
//无论是不是延迟消息都将被移除,如果想要保障非延迟消息执行的话,那么使用quitSafely()方法
public boolean quit() {
Looper looper = getLooper();
if (looper != null) {
looper.quit();
return true;
}
return false;
}
//和quit()方法的区别就是只有延迟方法才会被移除,当前的消息会被处理完成 API18支持
public boolean quitSafely() {
Looper looper = getLooper();
if (looper != null) {
looper.quitSafely();
return true;
}
return false;
}
//获取线程Id
public int getThreadId() {
return mTid;
}
}
其实整个HandlerThread
做的工作就是在Thread
中封装了Looper
对象,以此在创建的Handler
中能够进行异步的消息处理。
总结
如果有耗时操作可以考虑使用HandlerThread
机制。
创建HandlerThread
后必须首先调用start
方法,以此来准备子线程需要的Looper
对象,之后再创建Handler
对象时,才能在构造方法中调用new Handler(handlerThread.getLooper())
来使用Looper
对象,注意创建的先后顺序。