博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
(Source)HandlerThread
阅读量:6715 次
发布时间:2019-06-25

本文共 6163 字,大约阅读时间需要 20 分钟。

类注释

/** * Handy class for starting a new thread that has a looper. The looper can then be * used to create handler classes. Note that start() must still be called. */复制代码

HandlerThread是拥有Looper的一个线程类,它继承于Thread,当它调用 start() 方法后,通过getLooper()可以传递Looper给Handler,作为它初始化的参数,这样就完成了子线程的一个消息循环机制。

构造函数

public HandlerThread(String name, int priority) {    super(name);    mPriority = priority;}复制代码

传入线程的名字,和线程的优先级。

Looper

看到变量里有looper,

int mPriority; int mTid = -1; Looper mLooper;复制代码

再查到继承于Thread的run()方法:

@Overridepublic void run() {    mTid = Process.myTid();    Looper.prepare();    synchronized (this) {        mLooper = Looper.myLooper();        notifyAll();    }    Process.setThreadPriority(mPriority);    onLooperPrepared();    Looper.loop();    mTid = -1;}复制代码

先记录线程的TID,然后Looper.prepare,初始化好Looper,Looper内部初始化好MessageQueue,然后 notifyAll(),唤醒所有等待中的线程?啥,为什么呢?先搁置,看下去,接着设置线程优先级,然后,调用一个方法:onLooperPrepared() :

/** * Call back method that can be explicitly overridden if needed to execute some * setup before Looper loops. */protected void onLooperPrepared() {}复制代码

从注释看到,这个方法通常用于重写,在looper开始消息循环前进行一些初始化操作。回到上面的代码,最后就是开启 looper.loop() 开启消息循环。

getLooper()

从类注释看到,HandlerThread 是包含了Looper的子线程,不需要操作Looper就可以使用Handler机制,我们看到它的 getLooper() 方法:

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;}复制代码

如果线程因为某些原因,isAlive 返回 false,则返回 null 的looper。如果线程已经 start了,但是呢还未初始化好 looper,那么会一直阻塞:while (isAlive() && mLooper == null),细心的同学看到里面,有 wait() ,休眠线程,那么在什么时候被唤醒呢?噢噢,恍然大悟,就是上面的 run() 方法里面的 notifyAll() 啊,原来它唤醒的线程就是在这里,然后就接着返回正确的 looper啊,哈哈,SogaSoga。

quit

quit结束Looper的消息循环,有两个方法,safe quit 和 not safe quit,其都是调用 looper 的对应方法:

public boolean quit() {     Looper looper = getLooper();     if (looper != null) {         looper.quit();         return true;     }     return false; }复制代码
public boolean quitSafely() {    Looper looper = getLooper();    if (looper != null) {        looper.quitSafely();        return true;    }    return false;}复制代码

那么这两个方法有什么区别呢?我们还是看看 源码里面,这里举个例子吧:

public class HandlerThreadActivity extends AppCompatActivity {    private HandlerThread handlerThread;    private String TAG = "HandlerThreadTest";    private Handler handler;        @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_handler_thread);        Log.i(TAG,"onCreate");        handlerThread = new HandlerThread(TAG) {            @Override            protected void onLooperPrepared() {                super.onLooperPrepared();                Log.i(TAG,"onLooperPrepared, "+Thread.currentThread().getName());            }        };        handlerThread.start();        handler = new Handler(handlerThread.getLooper()) {            @Override            public void handleMessage(Message msg) {                switch (msg.what) {                    case 0x01:                        Log.i(TAG,"handleMessage, 0x01, start");                        try {                            Thread.sleep(10*1000);                        } catch (InterruptedException e) {                            e.printStackTrace();                        }                        Log.i(TAG,"handleMessage, 0x01, done");                        break;                    case 0x02:                        Log.i(TAG,"handleMessage, 0x02, done");                        break;                }            }        };        findViewById(R.id.btn_1).setOnClickListener(v -> {            handler.sendEmptyMessage(0x01);        });        findViewById(R.id.btn_2).setOnClickListener(v -> {            handler.sendEmptyMessage(0x02);        });    }    @Override    protected void onDestroy() {        super.onDestroy();        Log.i(TAG,"onDestroy");        //handlerThread.quit();        handlerThread.quitSafely();    }}复制代码

很简单的页面,点击按钮分别发送不同的消息,一条是阻塞线程的消息。在 onDestory() 中分别使用 quit() quitSafely() 观察log:

场景1,点击两次btn1,发送两个Message消息A1,A2,然后立即点击 btn2,发送一个Message消息B,立即退出这个activity

  • quit():
I/HandlerThreadTest: onCreateI/HandlerThreadTest: onLooperPrepared, HandlerThreadTestI/HandlerThreadTest: handleMessage, 0x01, startI/HandlerThreadTest: onDestroyI/HandlerThreadTest: handleMessage, 0x01, done复制代码

结合源码解析,quit() 直接退出,并remove所有在等待处理的消息,就是说,后面发送的A2和B被直接扔掉,而正在处理的 A1 就等待处理完成。

  • quitSafe():
I/HandlerThreadTest: onCreateI/HandlerThreadTest: onLooperPrepared, HandlerThreadTestI/HandlerThreadTest: handleMessage, 0x01, startI/HandlerThreadTest: onDestroyI/HandlerThreadTest: handleMessage, 0x01, doneI/HandlerThreadTest: handleMessage, 0x01, startI/HandlerThreadTest: handleMessage, 0x01, doneI/HandlerThreadTest: handleMessage, 0x02, done复制代码

有点不同,MessageQueue 的消息按照处理的时间 time 做了一个从小到大的排序,调用quitSafe的时刻假设为 currentTime,那么从MessageQueue的队列头开始寻找,直到有一个message.when>currentTime,那么就从这个message开始remove。也就是说,quitSafe时刻,的未来处理的消息全部会被remove调,而之前的消息会一直等待处理。我们来验证一下:

场景2:btn2的消息delay 10 秒,同样地点击两次btn1,发送两个Message消息A1,A2,然后立即点击 btn2,发送一个Message消息B,立即退出这个activity

findViewById(R.id.btn_2).setOnClickListener(v -> {    handler.sendEmptyMessageDelayed(0x02,10*1000);});复制代码
  • quit() :
I/HandlerThreadTest: onCreateI/HandlerThreadTest: onLooperPrepared, HandlerThreadTestI/HandlerThreadTest: handleMessage, 0x01, startI/HandlerThreadTest: onDestroyI/HandlerThreadTest: handleMessage, 0x01, done复制代码

跟场景1一样的log,quit() 这么残暴地直接remove所有的消息。

  • quitSafe():
I/HandlerThreadTest: onCreateI/HandlerThreadTest: onLooperPrepared, HandlerThreadTestI/HandlerThreadTest: handleMessage, 0x01, startI/HandlerThreadTest: onDestroyI/HandlerThreadTest: handleMessage, 0x01, doneI/HandlerThreadTest: handleMessage, 0x01, startI/HandlerThreadTest: handleMessage, 0x01, done复制代码

和上面解释符合。btn2发送的消息,在quitSafe的时刻相对来说是未来的事件,因而只有它被remove。

总结

  • HandlerThread 继承于 Thread,拥有 Looper,用于构造基于子线程的 handler 消息循环。
  • HandlerThread 的实例要 调用 start() 后才能 getLooper()
  • 清楚知道 quit() 和 quitSafe() 的区别
  • HandlerThread.getLooper() 有可能会阻塞线程

转载于:https://juejin.im/post/5c8d0d69f265da2dd168b29b

你可能感兴趣的文章
我的友情链接
查看>>
log4j配置
查看>>
去掉Intel集成显卡的桌面右键菜单
查看>>
我的友情链接
查看>>
python pip源配置
查看>>
clamav杀毒软件部署笔记
查看>>
小测试
查看>>
涨姿势一下:#include<>和#include""的区别
查看>>
quartz spring配置
查看>>
centos备份与还原
查看>>
fixed 兼容ie6
查看>>
To Be an Architect : 架构的一些基本概念
查看>>
数据恢复软件哪个好
查看>>
『火车进出栈问题 卡特兰数』
查看>>
第四天:HTTP&Tomcat
查看>>
python 文件和路径操作函数小结
查看>>
条件+努力=?
查看>>
HBase分布式安装
查看>>
随笔-文件的读写
查看>>
tcp 状态以及三次握手
查看>>