Android开发技术分享Android开发

HandlerThread的理解与剖析

2016-12-06  本文已影响168人  麦兜叮叮当

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并不适合,因为它只有一个线程,还得排队一个一个等着。

上一篇下一篇

猜你喜欢

热点阅读