HandlerThread继承至Thread。区别是HandlerThread内部自己创建了Looper,Looper又创建了MessageQueue,looper.loop内部不停的在检查messageQueue里面是否有新消息Message。有的话就交给message的target即handler去处理。通过查看HandlerThread的源代码。主要是在这个run方法里面
@Override
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
new一个Handler的时候将新创建的HandlerThread的Looper当做参数传递给自己,那么这个handler就和当前的HandlerThread关联在一起了,handler sendMessage的时候,其实就把消息发送给给looper里面创建的MessageQueue里面了。当前的handler就不是运行在UI主线程里面了,已经属于HandlerThread子线程了。下面给出一个简单的demo。
package com.figo.study.activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Toast;
import com.figo.study.R;
import java.util.Random;
public class HandlerThreadActivity extends AppCompatActivity {
private HandlerThread mHandlerThread;
private Handler mHandlerBindtoHandlerThread;
private boolean isScheduled;
private static final int WHAT = 123;
//测试产生一个随机数
int mResult = 0;
//默认运行在主线程,因为使用了默认的looper是ui主线程创建的
Handler mHandlerBindToUi = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case 1:
//更新ui,这里就简单弹个消息了
Toast.makeText(HandlerThreadActivity.this, "耗时操作完成,这里更新ui啊,mResult=" + mResult, Toast.LENGTH_SHORT).show();
break;
default:
break;
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_handler_thread);
findViewById(R.id.btn_test).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//方法一:使用handlerThread
useHandlerThread();
//方法二:使用handler+thread
//new Thread(new MyRunnable()).start();
}
});
}
@Override
protected void onResume() {
super.onResume();
}
@Override
protected void onPause() {
super.onPause();
//停止查询
isScheduled = false;
mHandlerBindtoHandlerThread.removeMessages(WHAT);
}
//方法一:使用HandlerThread
private void useHandlerThread() {
mHandlerThread = new HandlerThread("check-message-coming");
mHandlerThread.start();
mHandlerBindtoHandlerThread = new Handler(mHandlerThread.getLooper()) {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case WHAT: {
//当前handler已经运行在新线程mHandlerBindtoHandlerThread,所以这里可以运行耗时任务
loadData();
if (isScheduled) {
mHandlerBindtoHandlerThread.sendEmptyMessageDelayed(WHAT, 3000);//可设置延迟多少毫秒后继续执行耗时任务
}
}
break;
default:
break;
}
}
};
//发送一条消息去执行耗时任务
mHandlerBindtoHandlerThread.sendEmptyMessage(WHAT);
}
//方法二:使用Handler+Thread
class MyRunnable implements Runnable {
@Override
public void run() {
//执行耗时任务
loadData();
}
}
//耗时任务,加载数据
private void loadData() {
try {
//sleep模拟耗时操作,请使用你的耗时任务来代替Thread.sleep()
Thread.sleep(12000l);
Random r = new Random();
mResult = r.nextInt(10000);
} catch (Exception e) {
e.printStackTrace();
}
//执行完成通知ui主线程更新页面
mHandlerBindToUi.sendEmptyMessage(1);
}
@Override
protected void onDestroy() {
super.onDestroy();
//释放资源,避免looper一直在执行无限循环
mHandlerThread.quit();
}
}
使用handlerThread的优点是方便子线程和ui主线程即ActivityThread之间的消息通信。比如最近在做的一个表情相机,在相机预览获取到数据的时候在onPreviewFrame方法里,这是运行在主线程的,我直接使用mHandlerBindtoHandlerThread发条消息通知handlerThread子线程去执行耗时的人脸识别方法。识别成功后,我又使用在主线程创建的handler,发条消息出去,通知ui主线程更新页面。