HandlerThread是一个Android 已封装好的轻量级异步类。HandlerThread本质上是一个线程类,它继承了Thread;HandlerThread有自己的内部Looper对象,可以进行looper循环;通过获取HandlerThread的looper对象传递给Handler对象,可以在handleMessage方法中执行异步任务。创建HandlerThread后必须先调用HandlerThread.start()方法,Thread会先调用run方法,创建Looper对象。
一、HandlerThread + Handler使用详解
public class MainActivity extends AppCompatActivity {
private Handler mHandler;
private HandlerThread mHandlerThread;
private Handler uiHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case 2:
//更新UI
break;
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initHandlerThread();
//发送消息
mHandler.sendEmptyMessage(1);
}
private void initHandlerThread() {
//创建HandlerThread实例
mHandlerThread = new HandlerThread("handler_thread");
//开始运行线程
mHandlerThread.start();
//获取HandlerThread线程中的Looper实例
Looper loop = mHandlerThread.getLooper();
//创建Handler与该线程绑定。
mHandler = new Handler(loop) {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case 1:
Message message = new Message();
message.what = 2;
message.obj = "result";
uiHandler.sendMessage(message);
break;
default:
break;
}
}
};
}
@Override
protected void onDestroy() {
super.onDestroy();
//退出loop循环
mHandlerThread.quit();
}
}
一、HandlerThread源码解析
(1)HandlerThread源码
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;
}
public HandlerThread(String name, int priority) {
super(name);
mPriority = priority;
}
@Override
public void run() {
mTid = Process.myTid();
//创建looper实例
Looper.prepare();
synchronized (this) {
//获取当前线程的Looper实例
mLooper = Looper.myLooper();
//唤醒等待线程
notifyAll();
}
//设置线程优先级
Process.setThreadPriority(mPriority);
onLooperPrepared();
//开始循环
Looper.loop();
mTid = -1;
}
//返回与此线程关联的Looper
public Looper getLooper() {
//先判断当前线程是否启动了
if (!isAlive()) {
return null;
}
//如果这个线程已经启动,将会被阻塞,直到mLooper被初始化为止。
synchronized (this) {
while (isAlive() && mLooper == null) {
try {
//等待唤醒
wait();
} catch (InterruptedException e) {
}
}
}
//在HandlerThread的run()方法中赋值的mLooper
return mLooper;
}
public boolean quit() {
Looper looper = getLooper();
if (looper != null) {
//quit方法会将消息队列中的所有消息移除
looper.quit();
return true;
}
return false;
}
public boolean quitSafely() {
Looper looper = getLooper();
if (looper != null) {
//quitSafely会将消息队列所有的延迟消息移除,非延迟消息派发出去让Handler去处理。
looper.quitSafely();
return true;
}
return false;
}
(2)Looper.prepare源码
public static void prepare() {
prepare(true);
}
private static void prepare(boolean quitAllowed) {
//判断当前是否创建Looper实例,已经存在抛出异常
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
//创建Looper实例
sThreadLocal.set(new Looper(quitAllowed));
}
Handler内存泄漏:主线程的Looper对象的生命周期 = 该应用程序的生命周期。在Java中,非静态内部类 & 匿名内部类都默认持有外部类的引用
在Handler消息队列还有未处理的消息 / 正在处理消息时,此时若需销毁外部类MainActivity,但由于上述引用关系,垃圾回收器(GC)无法回收MainActivity,从而造成内存泄漏。
因为Looper的创建是在子线程中执行的,而调用getLooper方法则是在主线程进行的,这样我们就无法保障我们在调用getLooper方法时Looper已经被创建。在获取mLooper对象时会存在一个同步的问题,只有当线程创建成功并且Looper对象也创建成功之后才能获得mLooper的值,HandlerThread内部则通过等待唤醒机制解决了同步问题。
从源码可以看出当我们调用quit方法时,其内部实际上是调用Looper的quit方法而最终执行的则是MessageQueue中的removeAllMessagesLocked方法(Handler消息机制知识点),该方法主要是把MessageQueue消息池中所有的消息全部清空,无论是延迟消息(延迟消息是指通过sendMessageDelayed或通过postDelayed等方法发送)还是非延迟消息。
当调用quitSafely方法时,其内部调用的是Looper的quitSafely方法而最终执行的是MessageQueue中的removeAllFutureMessagesLocked方法,该方法只会清空MessageQueue消息池中所有的延迟消息,并将消息池中所有的非延迟消息派发出去让Handler去处理完成后才停止Looper循环,quitSafely相比于quit方法安全的原因在于清空消息之前会派发所有的非延迟消息