平時開發用到其餘線程嗎?都是如何處理的?面試
基本都用 RxJava 的線程調度切換,嗯對,就是那個 observeOn
和 subscribeOn
能夠直接處理,好比網絡操做,RxJava 提供了一個叫 io
線程的處理。微信
在 RxJava 的普遍使用以前,有使用過其餘操做方式嗎?好比 Handler 什麼的?網絡
固然用過呀。異步
那你講講 Handler 的工做原理吧。oop
Handler 工做流程基本包括 Handler、Looper、Message、MessageQueue 四個部分。但咱們在平常開發中,常常都只會用到 Handler 和 Message 兩個類。Message 負責消息的搭載,裏面有個 target
用於標記消息,obj
用於存放內容,Handler 負責消息的分發和處理。post
通常在開發中是怎麼使用 Handler 的?spa
官方不容許在子線程中更新 UI,因此咱們常常會把須要更新 UI 的消息直接發給處理器 Handler,經過重寫 Handler 的 handleMessage()
方法進行 UI 的相關操做。線程
那使用中就沒什麼須要注意的嗎?3d
有,Handler 若是設置爲私有變量的話,Android Studio 會報警告,提示可能會形成內存泄漏,這種狀況能夠經過設置爲靜態內部類 + 弱引用,或者在 onDestroy()
方法中調用 Handler.removeCallbacksAndMessages(null)
便可避免;code
總的來講這位面試的童鞋答的其實仍是沒那麼差,不過細節程度還不夠,因此南塵就來帶你們一塊兒走進 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()
裏面作了什麼?
至此,你大概明白了兩種方式的區別了。
本次內容可能講的比較多和亂,還望你們跟着到源碼中一步一步分析,最困難的時候,就是提高最大的時候!
我是南塵,只作比心的公衆號,歡迎關注我。
作不完的開源,寫不完的矯情。歡迎掃描下方二維碼或者公衆號搜索「nanchen」關注個人微信公衆號,目前多運營 Android ,盡本身所能爲你提高。若是你喜歡,爲我點贊分享吧~