注:一次OPPO面试的尴尬,所以回来恶补
原文链接借鉴
1 HandlerThread
1.1 主要作用
更简单的将一个一次性的多线程改进成可以循环利用的异步线程(个人理解)
1.2 原理
继承了Thread,实际上是一个使用Looper、Handler的线程。
继承了Thread,在run()方法中通过Looper.prepare()来创建消息队列,Looper.loop()来循环处理消息。
使用时开启HandlerThread,创建Handler与HandlerThread的Looper绑定,Handler以消息的方式通知HandlerThread来执行一个具体的任务。
1.3 特点
HandlerThread将loop转到子线程中处理,说白了就是将分担MainLooper的工作量,降低了主线程的压力,使主界面更流畅。
开启一个线程起到多个线程的作用。处理任务是串行执行,按消息发送顺序进行处理。HandlerThread本质是一个线程,在线程内部,代码是串行处理的。
但是由于每一个任务都将以队列的方式逐个被执行到,一旦队列中有某个任务执行时间过长,那么就会导致后续的任务都会被延迟处理。
HandlerThread拥有自己的消息队列,它不会干扰或阻塞UI线程。
对于网络IO操作,HandlerThread并不适合,因为它只有一个线程,还得排队一个一个等着。
HandlerThread内部维护了一个消息队列,避免多次创建和销毁子线程来进行操作。
2 HandlerThread的使用
2.1 HandlerThread使用步骤
(1)创建HandlerThread实例,参数字符串定义新线程的名称。
HandlerThread mHandlerThread =newHandlerThread("check-message-coming");
(2)启动HandlerThread线程。
mHandlerThread.start();
(3)创建Handler对象,将HandlerThread的Lopper作为参数,这样就完成了Handler对象与HandlerThread的Looper对象的绑定(这里的Handler对象可以看作是绑定在HandlerThread子线程中,所以handlerMessage里的操作是在子线程中运行的)。 重写handleMessage处理耗时操作。
Handler mCheckMsgHandler =newHandler(mHandlerThread.getLooper()){@OverridepublicvoidhandleMessage(Message msg){// 进行耗时操作}};
这样我们就可以使用mCheckMsgHandler对象以处理消息的形式来进行耗时操作,完成以后就可以切换到主线程的handler中来更新UI。
2.2 HandlerThread使用示例
依据刚才的步骤,来实现一个每秒更新数据的一个功能,这个功能可以用来更新股票、商品价格等。
创建和启动HandlerThread,handler绑定:新建Activity,在onCreate()中进行使用一个initBackThread()方法创建HandlerThread。等待mCheckMsgHandler 得到消息开始模拟耗时操作完成后切换到UI线程去更新UI,使用主线程的Handler也是一样的。
绑定按钮使用handler发送消息:一个开始按钮使mCheckMsgHandler发送消息去进行耗时操作,另一个按钮停止发送消息。标记isUpdate设置是否再次发送消息更新。
要记得在onPause()和onDestroy()中暂停更新和停止mHandlerThread以释放内存。
具体的源码分析【转载请注明出处:Android HandlerThread 源码分析 CSDN 废墟的树】
HandlerThread源码分析
HandlerThread构造函数
分析:该类开头就给出了一个描述:该类用于创建一个带Looper循环的线程,Looper对象用于创建Handler对象,值得注意的是在创建Handler
对象之前需要调用start()方法启动线程。这里可能有些人会有疑问?为啥需要先调用start()方法之后才能创建Handler呢?后面我们会解答。
上面的代码注释已经很清楚了,HandlerThread类有两个构造方法,不同之处就是设置当前线程的优先级参数。你可以根据自己的情况来设置优先
级,也可以使用默认优先级。
HandlerThread的run方法
分析:以上代码中的注释已经写得很清楚了,以上run方法主要作用就是调用了Looper.prepare和Looper.loop构建了一个循环线程。值得一提的
是,run方法中在启动loop循环之前调用了onLooperPrepared方法,该方法的实现是一个空的,用户可以在子类中实现该方法。该方法的作用是
在线程loop之前做一些初始化工作,当然你也可以不实现该方法,具体看需求。由此也可以看出,Google工程师在编写代码时也考虑到代码的可扩展性。牛B!
HandlerThread的其他方法
getLooper获得当前线程的Looper对象
分析:其实方法开头的英文注释已经解释的很清楚了:该方法主要作用是获得当前HandlerThread线程中的mLooper对象。
首先判断当前线程是否存活,如果不是存活的,这直接返回null。其次如果当前线程存活的,在判断线程的成员变量mLooper是否为null,如果为
null,说明当前线程已经创建成功,但是还没来得及创建Looper对象,因此,这里会调用wait方法去等待,当run方法中的notifyAll方法调用之后
通知当前线程的wait方法等待结束,跳出循环,获得mLooper对象的值。
总结:在获得mLooper对象的时候存在一个同步的问题,只有当线程创建成功并且Looper对象也创建成功之后才能获得mLooper的值。这里等待方法wait和run方法中的notifyAll方法共同完成同步问题。
quit结束当前线程的循环
分析:以上有两种让当前线程退出循环的方法,一种是安全的,一中是不安全的。至于两者有什么区别? quitSafely方法效率比quit方法标率低一点,但是安全。具体选择哪种就要看具体项目了。
总结:
1.HandlerThread适用于构建循环线程。
2.在创建Handler作为HandlerThread线程消息执行者的时候必须调用start方法之后,因为创建Handler需要的Looper参数是从HandlerThread类中获得,而Looper对象的赋值又是在HandlerThread的run方法中创建。
3.关于HandlerThread和Service的结合使用请参考另一篇博客:Android IntentService 源码分析
【转载请注明出处:Android HandlerThread源码分析 CSDN 废墟的树】