注:由於實際開發與參考答案會有所不一樣,再者怕誤導你們,因此這些面試題答案仍是本身去理解!面試官會針對簡歷中提到的知識點由淺入深提問,因此不要背答案,多理解。面試
Handler
1.談談消息機制Handler做用 ?有哪些要素 ?流程是怎樣的 ?
參考回答:安全
負責跨線程通訊,這是由於在主線程不能作耗時操做,而子線程不能更新UI,因此當子線程中進行耗時操做後須要更新UI時,經過Handler將有關UI的操做切換到主線程中執行。多線程
具體分爲四大要素
- Message(消息):須要被傳遞的消息,消息分爲硬件產生的消息(如按鈕、觸摸)和軟件生成的消息。
- MessageQueue(消息隊列):負責消息的存儲與管理,負責管理由 Handler發送過來的Message。讀取會自動刪除消息,單鏈表維護,插入和刪除上有優點。在其next()方法中會無限循環,不斷判斷是否有消息,有就返回這條消息並移除
- Handler(消息處理器):負責Message的發送及處理。主要向消息池發送各類消息事件(Handler.sendMessage())和處理相應消息事件(Handler.handleMessage()),按照先進先出執行,內部使用的是單鏈表的結構。
- Looper(消息池):負責關聯線程以及消息的分發,在該線程下從 MessageQueue獲取 Message,分發給Handler,Looper建立的時候會建立一個 MessageQueue,調用loop()方法的時候消息循環開始,其中會不斷調用messageQueue的next()方法,當有消息就處理,不然阻塞在messageQueue的next()方法中。當Looper的quit()被調用的時候會調用messageQueue的quit(),此時next()會返回null,而後loop()方法也就跟着退出。
具體流程以下
- 在主線程建立的時候會建立一個Looper,同時也會在在Looper內部建立一個消息隊列。而在創鍵Handler的時候取出當前線程的Looper,並經過該Looper對象得到消息隊列,而後Handler在子線程中經過MessageQueue.enqueueMessage在消息隊列中添加一條Message。
- 經過Looper.loop() 開啓消息循環不斷輪詢調用 MessageQueue.next(),取得對應的Message而且經過Handler.dispatchMessage傳遞給Handler,最終調用Handler.handlerMessage處理消息。
2.一個線程可否建立多個Handler,Handler跟Looper之間的對應關係 ?
參考回答:併發
- 一個Thread只能有一個Looper,一個MessageQueen,能夠有多個Handler
- 以一個線程爲基準,他們的數量級關係是: Thread(1) : Looper(1) : MessageQueue(1) : Handler(N)
3.軟引用跟弱引用的區別
參考回答:oop
- 軟引用(SoftReference):若是一個對象只具備軟引用,則內存空間充足時,垃圾回收器就不會回收它;若是內存空間不足了,就會回收這些對象的內存。只要垃圾回收器沒有回收它,該對象就能夠一直被程序使用。
- 弱引用(WeakReference):若是一個對象只具備弱引用,那麼在垃圾回收器線程掃描的過程當中,一旦發現了只具備弱引用的對象,無論當前內存空間足夠與否,都會回收它的內存。
- 二者之間根本區別在於:只具備弱引用的對象擁有更短暫的生命週期,可能隨時被回收。而只具備軟引用的對象只有當內存不夠的時候才被回收,在內存足夠的時候,一般不被回收。
4.Handler 引發的內存泄露緣由以及最佳解決方案
參考回答: 泄露緣由post
- Handler 容許咱們發送延時消息,若是在延時期間用戶關閉了 Activity,那麼該 Activity 會泄露。 這個泄露是由於 Message 會持有 Handler,而又由於 Java 的特性,內部類會持有外部類,使得 Activity 會被 Handler 持有,這樣最終就致使 Activity 泄露。 解決方案:
- 將 Handler 定義成靜態的內部類,在內部持有Activity的弱引用,並在Acitivity的onDestroy()中調用handler.removeCallbacksAndMessages(null)及時移除全部消息。
5.爲何系統不建議在子線程訪問UI?
參考回答: Android的UI控件不是線程安全的,若是在多線程中併發訪問可能會致使UI控件處於不可預期的狀態ui
這時你可能會問爲什麼系統不對UI控件的訪問加上鎖機制呢?由於spa
- 加鎖機制會讓UI訪問邏輯變的複雜
- 加鎖機制會下降UI的訪問效率,由於加鎖會阻塞某些線程的執行
6.Looper死循環爲何不會致使應用卡死?
參考回答:線程
- 主線程的主要方法就是消息循環,一旦退出消息循環,那麼你的應用也就退出了,Looer.loop()方法可能會引發主線程的阻塞,但只要它的消息循環沒有被阻塞,能一直處理事件就不會產生ANR異常。
- 形成ANR的不是主線程阻塞,而是主線程的Looper消息處理過程發生了任務阻塞,沒法響應手勢操做,不能及時刷新UI。
- 阻塞與程序無響應沒有必然關係,雖然主線程在沒有消息可處理的時候是阻塞的,可是隻要保證有消息的時候可以馬上處理,程序是不會無響應的。
7.使用Handler的postDealy後消息隊列會有什麼變化?
參考回答: 若是隊列中只有這個消息,那麼消息不會被髮送,而是計算到時喚醒的時間,先將Looper阻塞,到時間就喚醒它。但若是此時要加入新消息,該消息隊列的對頭跟delay時間相比更長,則插入到頭部,按照觸發時間進行排序,隊頭的時間最小、隊尾的時間最大orm
8.能夠在子線程直接new一個Handler嗎?怎麼作?
參考回答:
不能夠,由於在主線程中,Activity內部包含一個Looper對象,它會自動管理Looper,處理子線程中發送過來的消息。而對於子線程而言,沒有任何對象幫助咱們維護Looper對象,因此須要咱們本身手動維護。因此要在子線程開啓Handler要先建立Looper,並開啓Looper循環
9.Message能夠如何建立?哪一種效果更好,爲何?
參考回答:能夠經過三種方法建立:
- 直接生成實例Message m = new Message
- 經過Message m = Message.obtain
- 經過Message m = mHandler.obtainMessage()
後二者效果更好,由於Android默認的消息池中消息數量是10,然後二者是直接在消息池中取出一個Message實例,這樣作就能夠避免多生成Message實例。