平时开发用到其余线程吗?都是如何处理的?面试
基本都用 RxJava 的线程调度切换,嗯对,就是那个 observeOn
和 subscribeOn
能够直接处理,好比网络操做,RxJava 提供了一个叫 io
线程的处理。网络
在 RxJava 的普遍使用以前,有使用过其余操做方式吗?好比 Handler 什么的?异步
固然用过呀。oop
那你讲讲 Handler 的工做原理吧。post
Handler 工做流程基本包括 Handler、Looper、Message、MessageQueue 四个部分。但咱们在平常开发中,常常都只会用到 Handler 和 Message 两个类。Message 负责消息的搭载,里面有个 target
用于标记消息,obj
用于存放内容,Handler 负责消息的分发和处理。spa
通常在开发中是怎么使用 Handler 的?线程
官方不容许在子线程中更新 UI,因此咱们常常会把须要更新 UI 的消息直接发给处理器 Handler,经过重写 Handler 的 handleMessage()
方法进行 UI 的相关操做。3d
那使用中就没什么须要注意的吗?code
有,Handler 若是设置为私有变量的话,Android Studio 会报警告,提示可能会形成内存泄漏,这种状况能够经过设置为静态内部类 + 弱引用,或者在 onDestroy()
方法中调用 Handler.removeCallbacksAndMessages(null)
便可避免;orm
总的来讲这位面试的童鞋答的其实仍是没那么差,不过细节程度还不够,因此南尘就来带你们一块儿走进 Handler。
异步通讯准备 => 消息入队 => 消息循环 => 消息处理
异步通讯准备
假定是在主线程建立 Handler,则会直接在主线程中建立处理器对象 Looper
、消息队列对象 MessageQueue
和 Handler 对象。须要注意的是,Looper
和 MessageQueue
均是属于其 建立线程 的。Looper
对象的建立通常经过 Looper.prepareMainLooper()
和 Looper.prepare()
两个方法,而建立 Looper
对象的同时,将会自动建立 MessageQueue
,建立好 MessageQueue
后,Looper
将自动进入消息循环。此时,Handler
自动绑定了主线程的 Looper
和 MessageQueue
。
消息入队
工做线程经过 Handler
发送消息 Message
到消息队列 MessageQueue
中,消息内容通常是 UI 操做。发送消息通常都是经过 Handler.sendMessage(Message msg)
和 Handler.post(Runnabe r)
两个方法来进行的。而入队通常是经过 MessageQueue.enqueueeMessage(Message msg,long when)
来处理。
消息循环
主要分为「消息出队」和「消息分发」两个步骤,Looper
会经过循环 取出 消息队列 MessageQueue
里面的消息 Message
,并 分发 到建立该消息的处理者 Handler
。若是消息循环过程当中,消息队列 MessageQueue
为空队列的话,则线程阻塞。
消息处理Handler
接收到 Looper
发来的消息,开始进行处理。
Thread
只能绑定 1个循环器 Looper
,但能够有多个处理者 Handler
Looper
可绑定多个处理者 Handler
Handler
只能绑定 1 个 1 个循环器 Looper
前面咱们说到 Looper
是经过 Looper.prepare()
和 Looper.prepareMainLooer()
建立的,咱们不妨看看源码里面到底作了什么。
咱们不得不看看 Looper
的构造方法都作了什么。
显而易见,确实在建立了 Looper
对象的时候,自动建立了消息队列对象 MessageQueue
。
而 Looper.prepareMainLooper()
从名称也很容易看出来,是直接在主线程内建立对象了。而在咱们平常开发中,常常都是在主线程使用 Handler
,因此致使了不多用到 Looper.prepare()
方法。
而生成 Looper
和 MessageQueue
对象后,则自动进入消息循环:Looper.loop()
,咱们不妨再看看里面到底作了什么?
截图中的代码比较简单,你们应该不难看懂,咱们再看看如何经过 MessageQueue.next()
来取消息设置阻塞状态的。
咱们取消息采用了一个无限 for 循环,当没有消息的时候,则把标记位 nextPollTimeOutMillis
设置为 -1,在进行下一次循环的时候,经过 nativePollOnce()
直接让其处于线程阻塞状态。
再看看咱们的消息分发是怎么处理的,主要看上面的 msg.target.dispatchMessage(msg)
方法。
原来 msg.target
返回的是一个 Handler
对象,咱们直接看看 Handler.dipatchMessage(Message msg)
作了什么。
总结:
- 在主线程中
Looper
对象自动生成,无需手动生成。而在子线程中,必定要调用Looper.prepare()
建立Looper
对象。若是在子线程不手动建立,则没法生成Handler
对象。- 分发消息给
Handler
的过程为:根据出队消息的归属者,经过dispatchMessage(msg)
进行分发,最终回调复写的handleMessage(Message msg)
。- 在消息分发
dispatchMessage(msg)
方法中,会进行 1 次发送方式判断:
1. 若msg.callback
属性为空,则表明使用了post(Runnable r)
发送消息,则直接回调Runnable
对象里面复写的run()
。
2. 若msg.callback
属性不为空,则表明使用了sendMessage(Message msg)
发送消息,直接回调复写的handleMessage(msg)
。
咱们常常会在 Handler
的使用中建立消息对象 Message
,建立方式也有两个 new Message()
或者 Message.obtain()
。咱们一般都更青睐于 Message.obtain()
这种方式,由于这样的方式,能够有效避免重复建立 Message
对象。实际上在代码中也是显而易见的。
前面主要讲解了 Handler.sendMessage(Message msg)
这种常规使用方式,实际上,咱们有时候也会用 Handler.post(Runnable r)
进行处理,咱们固然应该看看里面是怎么处理的。
从官方注释能够看到,这会直接将 Runnable
对象加到消息队列中,咱们来看看 `getPostMessage(r) 到底作了什么。
咱们上面的分析是对的。在 getPostMessage(Runnable r)
方法中,咱们除了经过 Message.obtain()
方法来建立消息对象外,专门把 Runnable
对象赋值给了 callback
,这样才用了上面作消息分发的时候,经过这个标记来判断是用的 post()
仍是 sendMessage()
方式。
一直在说经过 sendMessage()
方式来发消息,到底这个消息是怎么发送的呢?
直接看 sendMessageAtTime()
。
enqueueMessage()
里面作了什么?
至此,你大概明白了两种方式的区别了。
本次内容可能讲的比较多和乱,还望你们跟着到源码中一步一步分析,最困难的时候,就是提高最大的时候!