日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

面试:Handler 的工作原理是怎样的?

發(fā)布時間:2024/4/17 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 面试:Handler 的工作原理是怎样的? 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

面試場景

平時開發(fā)用到其他線程嗎?都是如何處理的?

基本都用 RxJava 的線程調(diào)度切換,嗯對,就是那個?observeOn?和?subscribeOn?可以直接處理,比如網(wǎng)絡(luò)操作,RxJava 提供了一個叫?io?線程的處理。

在 RxJava 的廣泛使用之前,有使用過其他操作方式嗎?比如 Handler 什么的?

當(dāng)然用過呀。

那你講講 Handler 的工作原理吧。

Handler 工作流程基本包括 Handler、Looper、Message、MessageQueue 四個部分。但我們在日常開發(fā)中,經(jīng)常都只會用到 Handler 和 Message 兩個類。Message 負(fù)責(zé)消息的搭載,里面有個?target?用于標(biāo)記消息,obj?用于存放內(nèi)容,Handler 負(fù)責(zé)消息的分發(fā)和處理。

一般在開發(fā)中是怎么使用 Handler 的?

官方不允許在子線程中更新 UI,所以我們經(jīng)常會把需要更新 UI 的消息直接發(fā)給處理器 Handler,通過重寫 Handler 的?handleMessage()?方法進(jìn)行 UI 的相關(guān)操作。

那使用中就沒什么需要注意的嗎?

有,Handler 如果設(shè)置為私有變量的話,Android Studio 會報警告,提示可能會造成內(nèi)存泄漏,這種情況可以通過設(shè)置為靜態(tài)內(nèi)部類 + 弱引用,或者在?onDestroy()?方法中調(diào)用?Handler.removeCallbacksAndMessages(null)?即可避免;

正文

總的來說這位面試的童鞋答的其實還是沒那么差,不過細(xì)節(jié)程度還不夠,所以南塵就來帶大家一起走進(jìn) Handler。

Handler 工作流程淺析

異步通信準(zhǔn)備 => 消息入隊 => 消息循環(huán) => 消息處理

  • 異步通信準(zhǔn)備
    假定是在主線程創(chuàng)建 Handler,則會直接在主線程中創(chuàng)建處理器對象?Looper、消息隊列對象?MessageQueue?和 Handler 對象。需要注意的是,Looper?和?MessageQueue?均是屬于其?創(chuàng)建線程?的。Looper?對象的創(chuàng)建一般通過?Looper.prepareMainLooper()?和?Looper.prepare()?兩個方法,而創(chuàng)建?Looper?對象的同時,將會自動創(chuàng)建?MessageQueue,創(chuàng)建好?MessageQueue?后,Looper?將自動進(jìn)入消息循環(huán)。此時,Handler?自動綁定了主線程的?Looper?和?MessageQueue。

  • 消息入隊
    工作線程通過?Handler?發(fā)送消息?Message?到消息隊列?MessageQueue?中,消息內(nèi)容一般是 UI 操作。發(fā)送消息一般都是通過?Handler.sendMessage(Message msg)?和?Handler.post(Runnabe r)?兩個方法來進(jìn)行的。而入隊一般是通過?MessageQueue.enqueueeMessage(Message msg,long when)?來處理。

  • 消息循環(huán)
    主要分為「消息出隊」和「消息分發(fā)」兩個步驟,Looper?會通過循環(huán)?取出?消息隊列?MessageQueue?里面的消息?Message,并?分發(fā)?到創(chuàng)建該消息的處理者?Handler。如果消息循環(huán)過程中,消息隊列?MessageQueue?為空隊列的話,則線程阻塞。

  • 消息處理
    Handler?接收到?Looper?發(fā)來的消息,開始進(jìn)行處理。

  • 對于 Handler ,一些需要注意的地方

    • 1 個線程?Thread?只能綁定 1個循環(huán)器?Looper,但可以有多個處理者?Handler
    • 1 個循環(huán)器?Looper?可綁定多個處理者?Handler
    • 1 個處理者?Handler?只能綁定 1 個 1 個循環(huán)器?Looper

    常規(guī)情況下,這些相關(guān)對象是怎么創(chuàng)建的?

    前面我們說到?Looper?是通過?Looper.prepare()?和?Looper.prepareMainLooer()?創(chuàng)建的,我們不妨看看源碼里面到底做了什么。

    我們不得不看看?Looper?的構(gòu)造方法都做了什么。

    顯而易見,確實在創(chuàng)建了?Looper?對象的時候,自動創(chuàng)建了消息隊列對象?MessageQueue。

    而?Looper.prepareMainLooper()?從名稱也很容易看出來,是直接在主線程內(nèi)創(chuàng)建對象了。而在我們?nèi)粘i_發(fā)中,經(jīng)常都是在主線程使用?Handler,所以導(dǎo)致了很少用到?Looper.prepare()?方法。

    而生成?Looper?和?MessageQueue?對象后,則自動進(jìn)入消息循環(huán):Looper.loop(),我們不妨再看看里面到底做了什么?

    截圖中的代碼比較簡單,大家應(yīng)該不難看懂,我們再看看如何通過?MessageQueue.next()來取消息設(shè)置阻塞狀態(tài)的。

    我們?nèi)∠⒉捎昧艘粋€無限 for 循環(huán),當(dāng)沒有消息的時候,則把標(biāo)記位?nextPollTimeOutMillis?設(shè)置為 -1,在進(jìn)行下一次循環(huán)的時候,通過?nativePollOnce()?直接讓其處于線程阻塞狀態(tài)。

    再看看我們的消息分發(fā)是怎么處理的,主要看上面的?msg.target.dispatchMessage(msg)?方法。

    原來?msg.target?返回的是一個?Handler?對象,我們直接看看?Handler.dipatchMessage(Message msg)?做了什么。

    總結(jié):

    • 在主線程中?Looper?對象自動生成,無需手動生成。而在子線程中,一定要調(diào)用Looper.prepare()?創(chuàng)建?Looper?對象。如果在子線程不手動創(chuàng)建,則無法生成?Handler?對象。
    • 分發(fā)消息給?Handler?的過程為:根據(jù)出隊消息的歸屬者,通過?dispatchMessage(msg)?進(jìn)行分發(fā),最終回調(diào)復(fù)寫的?handleMessage(Message msg)。
    • 在消息分發(fā)?dispatchMessage(msg)?方法中,會進(jìn)行 1 次發(fā)送方式判斷:
      1. 若?msg.callback?屬性為空,則代表使用了?post(Runnable r)?發(fā)送消息,則直接回調(diào)?Runnable?對象里面復(fù)寫的?run()。
      2. 若?msg.callback?屬性不為空,則代表使用了?sendMessage(Message msg)?發(fā)送消息,直接回調(diào)復(fù)寫的?handleMessage(msg)。

    常規(guī)的消息 Message 是如何創(chuàng)建的?

    我們經(jīng)常會在?Handler?的使用中創(chuàng)建消息對象?Message,創(chuàng)建方式也有兩個?new Message()?或者?Message.obtain()。我們通常都更青睞于?Message.obtain()?這種方式,因為這樣的方式,可以有效避免重復(fù)創(chuàng)建?Message?對象。實際上在代碼中也是顯而易見的。

    Handler 的另外一種使用方式

    前面主要講解了?Handler.sendMessage(Message msg)?這種常規(guī)使用方式,實際上,我們有時候也會用?Handler.post(Runnable r)?進(jìn)行處理,我們當(dāng)然應(yīng)該看看里面是怎么處理的。

    從官方注釋可以看到,這會直接將?Runnable?對象加到消息隊列中,我們來看看 `getPostMessage(r) 到底做了什么。

    我們上面的分析是對的。在?getPostMessage(Runnable r)?方法中,我們除了通過?Message.obtain()?方法來創(chuàng)建消息對象外,專門把?Runnable?對象賦值給了?callback,這樣才用了上面做消息分發(fā)的時候,通過這個標(biāo)記來判斷是用的?post()?還是?sendMessage()?方式。

    到底是如何發(fā)消息的?

    一直在說通過?sendMessage()?方式來發(fā)消息,到底這個消息是怎么發(fā)送的呢?

    ?

    直接看?sendMessageAtTime()。

    enqueueMessage()?里面做了什么?

    至此,你大概明白了兩種方式的區(qū)別了。

    寫在最后

    本次內(nèi)容可能講的比較多和亂,還望大家跟著到源碼中一步一步分析,最困難的時候,就是提升最大的時候!

    轉(zhuǎn)載于:https://www.cnblogs.com/liushilin/p/8667917.html

    總結(jié)

    以上是生活随笔為你收集整理的面试:Handler 的工作原理是怎样的?的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。