面試題:
Handler相關
1. 談談Handler消息機制,有什麼作用,有哪些要素,流程是怎樣的?
2. 爲什麼系統不建議在子線程訪問UI?
3. 一個Thread可以有幾個Looper?幾個Handler?
4. 如何將一個Thread線程變成Looper線程?Looper線程有哪些特點?
5. 可以在子線程直接new一個Handler嗎?怎麼做?
6. Message可以如何創建,哪種效果最好?爲什麼?
7. 這裏的ThreadLocal有什麼作用?
8. 主線程中的Looper的輪詢死循環爲何沒有阻塞主線程?
9. 使用Handler的postDealy()後消息隊列會發生什麼變化?
1. 談談Handler消息機制,有什麼作用,有哪些要素,流程是怎樣的?
此節參考我另一篇文章,寫的是Handler的工作流程和關鍵對象間的關係的。
2. 爲什麼系統不建議在子線程訪問UI?
標準回答
首先UI控件是線程不安全的,如果多線程併發訪問UI控件可能出現不可預期的狀態
那爲什麼不對UI控件加上鎖呢?
- 加鎖會讓UI訪問的邏輯變得更加複雜
- 鎖機制會降低UI訪問的效率,因爲鎖會阻塞某些線程
鑑於以上幾點,安卓的UI訪問採用單線程模式來處理。如果在非UI線程訪問UI會拋出CalledFromWrongThreadException異常。
3. 一個Thread可以有幾個Looper?幾個Handler?
由於使用了ThreadLocal機制,所以註定了一個線程只能有一個Looper,但Handler可以new無數個。
4. 如何將一個Thread線程變成Looper線程?Looper線程有哪些特點?
經過如下3個步驟就可以將一個線程變成Looper線程,無參構造創建的Handler是和當前線程的Looper綁定的。
Looper.prepare();
Handler handler = new Handler();
Looper.loop();
looper線程跟普通線程不一樣的是可以使用Handler進行傳遞消息。
5. 可以在子線程直接new一個Handler嗎?怎麼做?
-
如果是子線程的Handler,看上一個步驟中的邏輯
-
如果是創建主線程的Handler,則需要傳入MainLooper
Handler mainHandler = new Handler(Looper.getMainLooper());
6. Message可以如何創建,哪種效果最好?爲什麼?
創建Message的三種方式:
Message message = Message.obtain();
Message message = handler.obtainMessage();
Message message = new Message();
前兩種都是從消息池中返回一個新的實例,能有效避免重複創建Message。
7. 這裏的ThreadLocal有什麼作用?
主要用來存儲Looper,保證Looper的唯一性。
8. 主線程中的Looper的輪詢死循環爲何沒有阻塞主線程?
主線程其實就是一個默認實現了Looper的無限循環的線程,而各個需要在主線程執行的邏輯都會通過Handler來處理,MessageQueue中沒有Message的時候,線程是不會卡住的,因爲什麼也沒有執行。而主線程在處理UI的操作或者Activity的生命週期在執行時,如果超過一定時間就會報ANR。
9. 使用Handler的postDealy()後消息隊列會發生什麼變化?
postDelay的Message並不是等待一段時間再放入MessageQueue,而是將當前Message的delay時間和隊頭的Message比較,按照觸發時間進行排序,到對應時間再喚醒並執行Message。