HandlerThread的理解与剖析

作者: 麦兜叮叮当 | 来源:发表于2016-12-06 21:53 被阅读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并不适合,因为它只有一个线程,还得排队一个一个等着。

    相关文章

      网友评论

        本文标题:HandlerThread的理解与剖析

        本文链接:https://www.haomeiwen.com/subject/kzprmttx.html