HandlerThread本质上就是一个普通Thread,只不过内部建立了Looper。那么HandlerThread相对于Thread来讲有什么优点呢,其实我也一直在思索,查了很多资料,就把理解的东西跟大家分享一下。
首先我们先剖析一下网上借鉴的HandlerThread的demo:
packagecom.example.xvhuichuang.lianxi;
importandroid.os.Bundle;
importandroid.os.Handler;
importandroid.os.HandlerThread;
importandroid.os.Message;
importandroid.support.v7.app.AppCompatActivity;
importandroid.text.Html;
importandroid.widget.TextView;
/**
* HandlerThread实例
*/
public classMainActivityextendsAppCompatActivity {
private static final intMSG_UPDATE_INFO=0x110;
privateTextViewmTvServiceInfo;
privateHandlerThreadmCheckMsgThread;
privateHandlermCheckMsgHandler;
private booleanisUpdateInfo;
//与UI线程管理的handler
privateHandlermHandler=newHandler();
@Override
protected voidonCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTvServiceInfo= (TextView) findViewById(R.id.text);
}
@Override
protected voidonResume() {
super.onResume();
//开始查询
isUpdateInfo=true;
mCheckMsgHandler.sendEmptyMessage(MSG_UPDATE_INFO);
/**
* 毋庸置疑,在这里通知HandlerThread更新
* HandlerThread的Handler发送信息
* 在HandlerThread的Handler的hanlderMessage中执行任务
*/
}
@Override
protected voidonPause() {
super.onPause();
//停止查询
isUpdateInfo=false;
mCheckMsgHandler.removeMessages(MSG_UPDATE_INFO);
}
private voidinitBackThread() {
mCheckMsgThread=newHandlerThread("check-message-coming");//为HandlerThread起一个名字
mCheckMsgThread.start();//这里启动HandlerThread
mCheckMsgHandler=newHandler(mCheckMsgThread.getLooper()) {//这里获得子线程的looper
@Override
public voidhandleMessage(Message msg) {
checkForUpdate();
/**
* 在这里通知UI线程的handler更新UI
*
*/
if(isUpdateInfo) {
mCheckMsgHandler.sendEmptyMessageDelayed(MSG_UPDATE_INFO,1000);
}
}
};
}
/**
* 模拟从服务器解析数据
*/
private voidcheckForUpdate() {
try{
//模拟耗时
Thread.sleep(1000);
mHandler.post(newRunnable() {
@Override
public voidrun() {
String result ="实时更新中,当前大盘指数:%d";
result = String.format(result,(int) (Math.random() *3000+1000));
mTvServiceInfo.setText(Html.fromHtml(result));
}
});
}catch(InterruptedException e) {
e.printStackTrace();
}
}
@Override
protected voidonDestroy() {
super.onDestroy();
//释放资源
mCheckMsgThread.quit();
}
}
代码不算长,那我们仔细的来看一下,首先onCreate里面并没有做太多的事,仅仅调用了initBackThread();方法,OK那我们来看一下这个方法实现了什么东西:
private voidinitBackThread() {
mCheckMsgThread=newHandlerThread("check-message-coming");//为HandlerThread起一个名字
mCheckMsgThread.start();//这里启动HandlerThread
mCheckMsgHandler=newHandler(mCheckMsgThread.getLooper()) {//这里获得子线程的looper
@Override
public voidhandleMessage(Message msg) {
checkForUpdate();
mCheckMsgHandler.sendEmptyMessageDelayed(MSG_UPDATE_INFO,1000);
}}};
}
很明显,在此方法里创建HandlerThread并启动,然后在Handler中得到此线程的Looper,对于Handler我们已经很熟悉了,我们通常在子线程中借助Handler来更新UI,在这里,Handler是为HandlerThread服务的,这里的handler的handleMessage中调用了checkForUpdate()方法,那我们继续跟进:
private voidcheckForUpdate() {
try{
//模拟耗时
Thread.sleep(1000);
mHandler.post(newRunnable() {
@Override
public voidrun() {
String result ="实时更新中,当前大盘指数:%d";
result = String.format(result,(int) (Math.random() *3000+1000));
mTvServiceInfo.setText(Html.fromHtml(result));
}});
}catch(InterruptedException e) {
e.printStackTrace();
}
}
很明显,这是在模拟从服务器所消耗的时间,然后借助UI线程的Handler更新UI,那我们看到了run()方法,都知道当我们使用Thread的时候都要实现run()方法,那这里也许你会疑问,怎么可以在子线程中更新UI呢?千万不要被误解了,我们都知道线程Thread实现了Runnable接口,但Runnable是一个接口,不是一个线程,一般线程会实现Runnable。所以如果我们使用匿名内部类是运行在UI主线程的,如果我们使用实现这个Runnable接口的线程类,则是运行在对应线程的。
OK,这里搞定了,我们再回到initBackThread()方法,这里最后通过boolean类型判断,若true就自身给自身发信息,那么这就实现了HandlerThread重复利用。最后在onResume发送消息,开始循环。
HandlerThread的特点
开启一个线程起到多个线程的作用。处理任务是串行执行,按消息发送顺序进行处理。相比多次使用new Thread(){…}.start()这样的方式节省系统资源。但是由于每一个任务都将以队列的方式逐个被执行到,一旦队列中有某个任务执行时间过长,那么就会导致后续的任务都会被延迟处理。(这点有点线程池的味道)
HandlerThread拥有自己的消息队列,它不会干扰或阻塞UI线程。
通过设置优先级就可以同步工作顺序的执行,而又不影响UI的初始化;
HandlerThread比较适用于单线程+异步队列的场景,比如IO读写操作,耗时不多而且也不会产生较大的阻塞。对于网络IO操作,HandlerThread并不适合,因为它只有一个线程,还得排队一个一个等着。