1. Handler 的前世今生
2. 為什么要Handler
- 子線程不能操作UI ,用
Handler
從子線程切換到主線程- 可以共用
Handler
實(shí)現(xiàn)異步操作
3. Handler 是什么羽莺?
Handler
是android
系統(tǒng)里面的一種消息處理機(jī)制
4. 如何使用Handler?
- 可以自己
new
一個(gè)Handler
,但是要注意handler
導(dǎo)致的內(nèi)存泄漏
?把Handler 定義成一個(gè)靜態(tài)內(nèi)部類
?在Activity
或者fragment
關(guān)閉時(shí)移除 還沒(méi)有執(zhí)行的延時(shí)消息- 通過(guò)任何一個(gè)view 是不是可以
getHandler
,但是要注意 有可能為空蹂喻,比如 這個(gè)view 的 attacheInfo 為空意思就是這個(gè)view 還沒(méi)有 attach 到 window 上从媚。- 還可以用過(guò) view 的 psot 方法催植。只要view 已經(jīng) attach 到window 上斑鸦,底層也是通過(guò)Handler 來(lái)實(shí)現(xiàn)的
5. Handler 消息種類窖贤?
- 同步消息
- 異步消息
- 屏障消息
6. Handler 如何發(fā)送消息砖顷?post 和 send 之間的區(qū)別
- 可以通過(guò)send 和post 兩種方式發(fā)送:
sendMessage(@NonNull Message msg)
sendEmptyMessage(int what)
sendEmptyMessageAtTime(int what, long uptimeMillis)
sendEmptyMessageDelayed(int what, long delayMillis)
sendMessageDelayed(@NonNull Message msg, long delayMillis)
sendMessageAtTime(@NonNull Message msg, long uptimeMillis)
sendMessageAtFrontOfQueue(@NonNull Message msg)
post(@NonNull Runnable r)
postAtTime(@NonNull Runnable r, long uptimeMillis)
// token 就相當(dāng)于給這個(gè) Message 打了一個(gè)標(biāo)簽,后期可以通過(guò) handler 的 removeCallbacksAndMessages 出入token 對(duì)消息進(jìn)行移除赃梧。
postAtTime(@NonNull Runnable r, @Nullable Object token, long uptimeMillis)
postDelayed(@NonNull Runnable r, long delayMillis)
postDelayed(Runnable r, int what, long delayMillis) // app 調(diào)用不了
postDelayed(@NonNull Runnable r, @Nullable Object token, long delayMillis)
postAtFrontOfQueue(@NonNull Runnable r) //
上面的所有發(fā)送消息的方法(除sendMessageAtFrontOfQueue 以外)最終都會(huì)調(diào)用到handler 的 一個(gè) 叫 sendMessageAtTime(@NonNull Message msg, long uptimeMillis)滤蝠,在這個(gè)方法里面 調(diào)用enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,long uptimeMillis)把消息添加到消息隊(duì)列里面postAtFrontOfQueue(@NonNull Runnable r) 會(huì)調(diào)用 sendMessageAtFrontOfQueue 方法,在sendMessageAtFrontOfQueue 里面調(diào)用enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg, long uptimeMillis)
總的來(lái)說(shuō)就是 最終調(diào)用enqueueMessage 把消息入隊(duì)授嘀,這兒涉及到是三個(gè)參數(shù)物咳,
1: 隊(duì)列本身
2:消息本身
3:該消息執(zhí)行的準(zhǔn)確時(shí)間。
非延時(shí)消息:當(dāng)前系統(tǒng)時(shí)間
延時(shí)小時(shí):當(dāng)前系統(tǒng)時(shí)間+你要延時(shí)的時(shí)間
如果該消息是指明放在隊(duì)頭蹄皱,那么時(shí)間為0
面試如何回答:Handler 可以通過(guò)send 和 post 兩種方式發(fā)送消息览闰,這種兩種方式都可以發(fā)送即使消息,延時(shí)消息巷折,以及直接把消息發(fā)送到隊(duì)列的頭部压鉴,send 還可以發(fā)送空消息,但是不管通過(guò)哪種方handler 內(nèi)部都會(huì)封裝成一個(gè)Message 對(duì)象(如果是post 或者發(fā)的一個(gè)空消息)并且計(jì)算出消息執(zhí)行的確切時(shí)間锻拘,如果是即使消息晴弃,時(shí)間就是當(dāng)前系統(tǒng)時(shí)間,如果是延時(shí)消息就是當(dāng)前系統(tǒng)時(shí)間+延時(shí)的時(shí)間逊拍,如果是發(fā)送到隊(duì)列頭部時(shí)間就是0上鞠,之所以要計(jì)算時(shí)間就是因?yàn)槿腙?duì)的時(shí)候需要通過(guò)時(shí)間排序,最終調(diào)用一個(gè)叫enqueueMessage 的方法芯丧,在這個(gè)方法里面調(diào)用隊(duì)列自己的入隊(duì)方法芍阎,把消息本身和計(jì)算出來(lái)的時(shí)間傳遞進(jìn)去進(jìn)行入隊(duì)
7. Handler 消息如何入隊(duì)?如何排序缨恒?延時(shí)消息入隊(duì)機(jī)制谴咸?
8. Handler 消息如如何入隊(duì)和出隊(duì)?
- 入隊(duì):
MessageQueue 實(shí)際上是一個(gè)鏈表的的結(jié)構(gòu)骗露,每一個(gè)Message 對(duì)象里面有一個(gè) next 變量用來(lái)指向它的下一個(gè)消息岭佳。Handler 只負(fù)責(zé)把消息交給MessageQueue,真正入隊(duì)的操作時(shí) 隊(duì)列自己完成的萧锉,隊(duì)列在對(duì)消息入隊(duì)時(shí)會(huì)更具消息執(zhí)行的時(shí)間進(jìn)行排序珊随,如果隊(duì)列是空 或者執(zhí)行時(shí)間為0 那么就排在頭部,如果頭部已經(jīng)有了,那么內(nèi)部有一個(gè)for 循環(huán) 叶洞,從頭部該是比較鲫凶,如果該消息執(zhí)行的時(shí)間小于頭部時(shí)間 ,那么就插入到頭部衩辟,然把自己的next 指向原來(lái)的頭部螟炫。如果消息執(zhí)行的時(shí)間大于頭部,那么就和后面的挨個(gè)比較艺晴,直到大于前面并且小于后面豹绪,那么就插入到他們中間揽思,如果比到最后一個(gè)幕庐,發(fā)現(xiàn)還是比最后一個(gè)大鹿寨,那么就插入到隊(duì)列最后一個(gè)却音。
如果發(fā)送的消息進(jìn)過(guò)計(jì)算后會(huì) 插入入到頭部士败,如果發(fā)現(xiàn)主線程被阻塞了就會(huì)去喚醒述召,如果沒(méi)有則不喚醒心铃,入隊(duì)完成满着。- 出隊(duì):
從隊(duì)列的頭部開(kāi)始取谦炒,如果頭部有,用頭部消息執(zhí)行的時(shí)間和當(dāng)前系統(tǒng)時(shí)間進(jìn)行比較风喇,如果執(zhí)行時(shí)間小于 小于等于系統(tǒng)時(shí)間宁改,那么該消息滿足執(zhí)行條件,就通過(guò)消息找到Handler魂莫,然后調(diào)用Handler 的 dispatchMessage 方法把消息傳給了 Handler还蹲,最終調(diào)用handler 的 handleMessage 對(duì)消息進(jìn)行處理,如果不滿足耙考,那么用消息執(zhí)行的時(shí)間減去系統(tǒng)時(shí)間計(jì)算出需要等待的時(shí)間谜喊,然后阻塞在哪兒了,如果中途沒(méi)有其他人喚醒倦始,到了等待時(shí)間后會(huì)自動(dòng)被喚醒斗遏。
9. 為什么Handler 能把消息從子線程發(fā)送到主線程?
10. 如何在子線程中創(chuàng)建Handler?
11. 為什么UI 線程不會(huì)阻塞?
Handler
- 發(fā)送消息鞋邑,
- 處理消息
Looper
循環(huán)器诵次,循環(huán)從消息隊(duì)列里面取出消息,然后交給handler 處理
Message
消息的包裝類枚碗。里面可以用來(lái)傳遞數(shù)據(jù)
MessageQueue
消息隊(duì)列逾一,它是一個(gè)假的隊(duì)列,它本質(zhì)是一個(gè) 鏈表模擬的隊(duì)列