尊重原创,转载请注明出处:http://blog.csdn.net/a740169405/article/details/50257001

HandlerThread概述

  1. HandlerThread是一个线程类
  2. HandlerThread内部创建了一个消息队列,其他线程可以通过Handler向其发送消息。
  3. HandlerThread按照消息的发送顺序依次对消息进行处理。
  4. HandlerThread在所有消息执行完毕后,线程并不会自动退出,消息队列任然在等待新任务。

一、HandlerThread内部消息队列的初始化

在线程成功执行后,HandlerThread创建了一个消息队列,用来接收其他线程发来的消息:

@Overridepublic void run() {    mTid = Process.myTid();    // 为当前线程创建Looper    Looper.prepare();    synchronized (this) {    // 获取当前线程Looper对象        mLooper = Looper.myLooper();        // 唤醒其他等待线程        notifyAll();    }    Process.setThreadPriority(mPriority);    // mLooper对象初始化完成后回调    onLooperPrepared();    // 开始循环读取消息队列里的消息    Looper.loop();    mTid = -1;}

该方法调用了Looper.prepare();创建了一个消息队列。这样,该线程就能接收handler发送的消息了。
最后调用了Looper.loop();开始循环读取消息。

二、向HandlerThread发送消息

@Overrideprotected void onCreate(Bundle savedInstanceState) {    super.onCreate(savedInstanceState);    // 创建线程,命名为"myHandlerThread"    HandlerThread handlerThread = new HandlerThread("myHandlerThread");    // 启动线程    handlerThread.start();    // 创建Handler,并指定使用HandlerThread的消息队列来处理消息    MyHandler myHandler = new MyHandler(handlerThread.getLooper());    // 发送一条空消息给消息队列    myHandler.obtainMessage().sendToTarget();}public static class MyHandler extends Handler {    public MyHandler(Looper looper) {        super(looper);    }    @Override    public void handleMessage(Message msg) {        super.handleMessage(msg);        // 收到消息后,打印出当前线程的名字        Log.e(TAG, "current Thread name : " + Thread.currentThread().getName());    }}

我在主线程中初始化了一个HandlerThread线程,并启动了该线程。
向HandlerThread的消息队列发送了一条消息,消息收到后输出了当前线程的名字。

demo.chen.com.myapplication E/HandlerThreadActivity: current Thread name : myHandlerThread

后台输出的名字正是我创建线程的时候传递进去的。
通过上面的例子我们发现,向handlerThread发送的消息,是由HandlerThread线程来处理的。

三、HandlerThread锁机制:

大家注意这一段代码:

synchronized (this) {    mLooper = Looper.myLooper();    notifyAll();}

加锁是为了确保其他现成获取该线程的Looper时不为空。
我们再看看HandlerThread提供的获取Looper的方法:

    public Looper getLooper() {    // 如果线程未启动,返回空        if (!isAlive()) {            return null;        }        // If the thread has been started, wait until the looper has been created.        synchronized (this) {            while (isAlive() && mLooper == null) {                try {                // 如果线程已启动,并且消息队列尚未初始化,进入等待状态                    wait();                } catch (InterruptedException e) {                }            }        }        return mLooper;    }

代码的意思很简单,如果Looper还未创建,则进入等待状态,直到Looper被创建。

我尝试写一个HandlerThread的子类来验证一下:

public static class MyHandlerThread extends HandlerThread {    public MyHandlerThread(String name) {        super(name);    }    @Override    public void run() {        try {            // 在线程启动后,初始化消息队列之前,sleep三秒            Thread.sleep(3000);        } catch (InterruptedException e) {            e.printStackTrace();        }        // 调用父类的run方法初始化消息队列        super.run();    }    @Override    public Looper getLooper() {        return super.getLooper();    }}

逻辑很简单,重写run方法,在调用父类run方法进行Looper初始化之前让线程sleep三秒。
添加一些Log:

MyHandlerThread handlerThread = new MyHandlerThread("myHandlerThread");// 线程启动前,先打个log记录当前时间SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");Log.e(TAG, "current time = " + formatter.format(new Date()));handlerThread.start();Looper looper = handlerThread.getLooper();// 在getLooper();之后打印log记录当前时间Log.e(TAG, "get looper success, send message, time = " + formatter.format(new Date()));MyHandler myHandler = new MyHandler(looper);// 发送消息myHandler.obtainMessage().sendToTarget();

再看看log:

E/HandlerThreadActivity: current time = 2015-12-11 08:45:03
E/HandlerThreadActivity: get looper success, send message, time = 2015-12-11 08:45:06
E/HandlerThreadActivity: current Thread name : myHandlerThread

从log中可以看出主线程等待了三秒,之所以加锁是为了防止在looper未被初始化之前,其他线程调用getLooper方法得到空对象。

注意:

一般我们是不需要重写HandlerThread类,只需要使用Handler对象向HandlerThread的消息队列发送消息,在handleMessage函数里处理消息,就可以了,且处理消息的线程是HandlerThread这个线程。

上面的例子中,我在消息队列初始化之前sleep了3秒,导致了主线程在getLooper的时候等待了3秒,也就是说有可能造成主线程ANR。

四、HandlerThread的退出

需要注意的是,一旦执行Looper.loop();线程便进入循环获取消息状态,也就是说线程不会自己停止,我们可以一直往线程发送消息,如果需要停止线程,只要调用HandlerThread对象的quit();或者quitSafely();函数,这两个函数其实只是调用了Looper对象的quit();或者quitSafely();函数:
HandlerThread的quit();函数:

public boolean quit() {    // 获取当前线程的Looper    Looper looper = getLooper();    if (looper != null) {    // 立即停止Looper的循环,不在处理未处理完的消息        looper.quit();        return true;    }    return false;}

HandlerThread的quitSafely();函数:

public boolean quitSafely() {    // 获取当前线程的Looper    Looper looper = getLooper();    if (looper != null) {        // 打上需要停止循环的标志,等到消息都处理完以后,再推出循环        looper.quitSafely();        return true;    }    return false;}

这两者的区别在于,调用quit();会直接终止消息队列的循环,如果队列中还有其他消息未处理,将不会被处理。
而调用quitSafely();函数则是给消息队列打上退出循环的标记,在所有消息处理完成以后,Looper自动退出循环,从而线程也就会结束。

总结:

1. HandlerThread类是google提供的一个,在线程内创建消息循环队列的线程API,让除了主线程以外的子线程也具有消息处理能力。2. 使用时记得先调用HandlerThread的run方法启动线程3. 在创建Handler时使用HandlerThread的Looper对象。4. 确认所有任务都处理完成以后,记得调用HandlerThread推出函数,建议使用quitSafely();这样会等到所有消息都处理完后再推出线程。

应用:
HandlerThread在IntentService中应用到。
关于IntentService的项管内容,大家可以阅读我的另一片博客:Android IntentService的使用与源码解析

更多相关文章

  1. Android中的几种多线程实现
  2. Android(安卓)Toast 用法总结
  3. Android界面刷新
  4. 走进Java Android(安卓)的线程世界(三)Hander消息机制
  5. Android(安卓)第三方类库简单使用之EventBus
  6. android AsynTask 实现原理
  7. Android(安卓)利用Handle 切换的主线程更新UI
  8. Java(Android)线程池详解
  9. Android(安卓)ListView刷新 (Handler/Service)

随机推荐

  1. 单个mysql查询,用于选择25个记录(9 + 16),使
  2. Mysql - 加入多个ID并结束连接列?
  3. 安装mysql的时候最后执行一直停留在Write
  4. mybaties日常开发总结
  5. 使用Python 3更新MySQL数据库
  6. Solr之搭建Solr6.0服务并从Mysql上导入数
  7. 无法使用php连接到mysql
  8. 使用格式化输出自动扩展Python列表
  9. 在SQL中声明@变量返回错误
  10. 从Node.js上的mysql结果JSON获取一个Arra