Android 面試 15 家大廠,這個問題是必問!

Android入墳之路發表於2019-04-10

年後面了十餘家大廠,每家都會問的一個問題就是Android的訊息機制!可見Android的訊息機制是多麼重要!

訊息機制之所以這麼重要是因為Android應用程式是通過訊息來驅動的,Android某種意義上也可以說成是一個以訊息驅動的系統,UI、事件、生命週期都和訊息處理機制息息相關,並且訊息處理機制在整個Android知識體系中也是尤其重要,在太多的原始碼分析的文章講得比較繁瑣,很多人對整個訊息處理機制依然是懵懵懂懂,這篇文章通過一些問答的模式結合Android主執行緒(UI執行緒)的工作原理來講解,原始碼註釋很全,還有結合流程圖,如果你對Android 訊息處理機制還不是很理解,我相信只要你靜下心來耐心的看,肯定會有不少的收穫的。

概述

1、我們先說下什麼是Android訊息處理機制?

訊息處理機制本質:一個執行緒開啟迴圈模式持續監聽並依次處理其他執行緒給它發的訊息。

簡單的說:一個執行緒開啟一個無限迴圈模式,不斷遍歷自己的訊息列表,如果有訊息就挨個拿出來做處理,如果列表沒訊息,自己就堵塞(相當於wait,讓出cpu資源給其他執行緒),其他執行緒如果想讓該執行緒做什麼事,就往該執行緒的訊息佇列插入訊息,該執行緒會不斷從佇列裡拿出訊息做處理。

2、Android訊息處理機制的工作原理?

打個比方:公司類比App

  • PM 的主要工作是設計產品,寫需求文件,改需求,中途改需求,提測前改需求...

  • UI 主要工作是UI設計,互動等。

  • RD 工作我就不說了

  • CEO 不解釋。

公司開創之後(App啟動),那麼CEO開始幹活了(主執行緒【UI執行緒】啟動),這時候CEO開啟了無限迴圈工作狂模式,自己的公司沒辦法啊(相當於UI主執行緒轉成Looper執行緒【原始碼裡面有】)

CEO招了一名RD(new Handler 例項)並把告訴PM和UI,如果你們有什麼任務和需求就讓RD(Handler例項)轉告給我(CEO)。RD會把PM和UI的需求(Message)一條條記到CEO的備忘錄裡(MessageQueue)。

CEO 無限迴圈的工作就是不斷檢視備忘錄,看有什麼任務要做,有任務就從備忘錄一條一條拿出任務來,然後交給這一名RD(Handler 例項)去處理(畢竟CEO 不會寫程式碼 囧...)。當然如果備忘錄都做完了,這時候CEO就會去睡覺(執行緒堵塞【簡單理解成執行緒wait】,讓出CPU資源,讓其他執行緒去執行)。

但是這個備忘錄有個特殊的功能就是沒有任務的時候突然插入第一條任務(從無到有)就會有鬧鐘功能叫醒CEO起床繼續處理備忘錄。 整個訊息處理機制的工作原理基本就是這樣的。後面會有原始碼分析,你再來結合這個場景,會更好理解一些。

這裡先給一張Android訊息處理機制流程圖和具體執行動畫,如果看不懂沒事,接著往下看(後面會結合Android UI主執行緒來講解),然後結合著圖和動畫一塊看更能理解整個機制的實現原理。

Android 面試 15 家大廠,這個問題是必問!
Android 面試 15 家大廠,這個問題是必問!

3、Looper、Handler、MessageQueue,Message作用和存在的意義?

  • **Looper **
    我們知道一個執行緒是一段可執行的程式碼,當可執行程式碼執行完成後,執行緒生命週期便會終止,執行緒就會退出,那麼做為App的主執行緒,如果程式碼段執行完了會怎樣?,那麼就會出現App啟動後執行一段程式碼後就自動退出了,這是很不合理的。

    所以為了防止程式碼段被執行完,只能在程式碼中插入一個死迴圈,那麼程式碼就不會被執行完,然後自動退出,怎麼在在程式碼中插入一個死迴圈呢?

    那麼Looper出現了,在主執行緒中呼叫Looper.prepare()...Looper.loop()就會變當前執行緒變成Looper執行緒(可以先簡單理解:無限迴圈不退出的執行緒),Looper.loop()方法裡面有一段死迴圈的程式碼,所以主執行緒會進入while(true){...}的程式碼段跳不出來,但是主執行緒也不能什麼都不做吧?

    其實所有做的事情都在while(true){...}裡面做了,主執行緒會在死迴圈中不斷等其他執行緒給它發訊息(訊息包括:Activity啟動,生命週期,更新UI,控制元件事件等),一有訊息就根據訊息做相應的處理,Looper的另外一部分工作就是在迴圈程式碼中會不斷從訊息佇列挨個拿出訊息給主執行緒處理。

  • MessageQueue
    MessageQueue 存在的原因很簡單,就是同一執行緒在同一時間只能處理一個訊息,同一執行緒程式碼執行是不具有併發性,所以需要佇列來儲存訊息和安排每個訊息的處理順序。多個其他執行緒往UI執行緒傳送訊息,UI執行緒必須把這些訊息保持到一個列表(它同一時間不能處理那麼多工),然後挨個拿出來處理,這種設計很簡單,我們平時寫程式碼其實也經常這麼做。每一個Looper執行緒都會維護這樣一個佇列,而且僅此一個,這個佇列的訊息只能由該執行緒處理。

  • Handler
    簡單說Handler用於同一個程式的執行緒間通訊。Looper讓主執行緒無限迴圈地從自己的MessageQueue拿出訊息處理,既然這樣我們就知道處理訊息肯定是在主執行緒中處理的,

    那麼怎樣在其他的執行緒往主執行緒的佇列裡放入訊息呢?其實很簡單,我們知道在同一程式中執行緒和執行緒之間資源是共享的,也就是對於任何變數在任何執行緒都是可以訪問和修改的,只要考慮併發性做好同步就行了,那麼只要拿到MessageQueue 的例項,就可以往主執行緒的MessageQueue放入訊息,主執行緒在輪詢的時候就會在主執行緒**處理這個訊息。

    那麼怎麼拿到主執行緒 MessageQueue的例項,是可以拿到的(在主執行緒下

    mLooper = Looper.myLooper();mQueue = mLooper.mQueue;),
    複製程式碼
  • 但是Google 為了統一新增訊息和訊息的回撥處理,又專門構建了Handler類,你只要在主執行緒構建Handler類,那麼這個Handler例項就獲取主執行緒MessageQueue例項的引用

    (獲取方式mLooper = Looper.myLooper();mQueue = mLooper.mQueue;)

    Handler 在sendMessage的時候就通過這個引用往訊息佇列裡插入新訊息。Handler 的另外一個作用,就是能統一處理訊息的回撥。這樣一個Handler發出訊息又確保訊息處理也是自己來做,這樣的設計非常的贊。具體做法就是在佇列裡面的Message持有Handler的引用(哪個handler 把它放到佇列裡,message就持有了這個handler的引用),然後等到主執行緒輪詢到這個message的時候,就來回撥我們經常重寫的Handler的handleMessage(Message msg)方法。

  • Message
    Message 很簡單了,你想讓主執行緒做什麼事,總要告訴它吧,總要傳遞點資料給它吧,Message就是這個載體。

今天帶著大家先簡單瞭解了下Handler機制的工作流程,後面會帶著大家從原始碼的角度分析Handler機制,讓大家由內到外完全掌握Android的訊息機制!



相關文章