說起Handler摄欲,大家都不陌生郑趁,不管是在開發(fā)中還是面試當(dāng)中刊驴,基本都會問到Handler,那么寡润,Handler的機制是怎樣的呢捆憎?現(xiàn)在我們就來分析下
Handler介紹
Handler機制指的是Android的消息機制,它的使用很簡單梭纹,通過它可以輕松的將一個任務(wù)切換到Handler所在的線程去執(zhí)行躲惰,我們用的最多的地方也就是Handler刷新UI的功能,其實变抽,它還有很多用途础拨,比如子線程中進行消耗的I/O操作氮块,讀取文件等,而我們用它來刷新UI诡宗,是因為子線程無法刷新UI滔蝉,可以通過它來切換回主線程執(zhí)行,因此塔沃,本質(zhì)來說蝠引,它只是常用來刷新UI而已
Handler機制
Handler機制也就是消息機制,它與MessageQueue和Looper完成一個體系蛀柴,我們來看看他們?nèi)叩年P(guān)系
MessageQueue
從字面意思我們不難知道螃概,它是個消息隊列,也就是說鸽疾,它存儲了所有的消息吊洼,也可以叫它消息列表,我們從Handler的sendMessage發(fā)出的消息都會被存儲到這里面
Looper
Looper翻譯成中文就是循環(huán)肮韧,意思就是消息循環(huán)融蹂,它會無限循環(huán)的從MessageQueue中讀取消息旺订,如果有則處理弄企,沒有就一直等待,MessageQueue雖然是消息隊列区拳,然而它并沒有能對消息進行處理的操作拘领,因此,需要Looper的支持
Handler
Handler主要負責(zé)發(fā)送消息到MessageQueue樱调,它在創(chuàng)建的時候约素,會采用當(dāng)前線程的Looper來構(gòu)成消息系統(tǒng),但是注意了笆凌,線程默認是沒有Looper的圣猎,而使用Handler就一定需要有Looper才可以執(zhí)行,主線程之所以能使用Handler乞而,那是因為主線程是ActivityThread送悔,ActivityThread被創(chuàng)建的時候會初始化Looper,所以它能使用Handler爪模,所以主線程也叫UI線程
所以欠啤,我們大概就知道了Handler是怎么工作的了,Handler創(chuàng)建完之后屋灌,通過Handler的send方法將一個消息存儲到MessageQueue中洁段,然后Looper循環(huán)從MessageQueue中讀取消息并且處理,處理完之后如果還有消息就繼續(xù)處理共郭,否則就等待
上面就是Handler和MessageQueue祠丝,Looper的關(guān)系疾呻,這三者其實是一個整體,我們來思考下幾個問題写半,①:為什么不能再子線程中更新UI罐韩,②:為什么需要用Handler來刷新UI,③:如果非要在子線程中更新UI怎么辦污朽,現(xiàn)在我們來說說這幾個問題
問題一:
之所以Android不允許在子線程中更新UI散吵,那是因為,子線程是可以無限被創(chuàng)建的蟆肆,我們假想下矾睦,如果有5條子線程,每條子線程都有一個UI控件炎功,我們?nèi)ニ⑿耈I的時候會出現(xiàn)什么后果枚冗,后果就是我們達不到預(yù)期的UI控件刷新順序,我們可能想控件1先刷新控件2再刷新蛇损,有可能就會出現(xiàn)相反的順序赁温,也可能同時刷新,并且淤齐,如果有N條子線程股囊,線程并發(fā)問題會更嚴重,所以Android必須要在UI線程中更新UI更啄,也有可能會問稚疹,為什么不對UI控件上鎖呢?原因有兩個:1祭务,上鎖會讓UI訪問邏輯復(fù)雜化内狗,不靈活,如果我需要在其他線程訪問UI的話义锥,比較難處理 2柳沙,加鎖會阻塞線程的執(zhí)行,所以拌倍,這就是為什么我們需要在UI線程中更新UI的原因
問題二:
我們知道赂鲤,在異步線程中訪問網(wǎng)絡(luò)請求之后,需要刷新UI的時候是不能再子線程中執(zhí)行的贰拿,Handler可以做到刷新UI蛤袒,那是因為Handler在創(chuàng)建的時候會調(diào)用當(dāng)前線程的Looper對象,Looper對象是對消息的處理膨更,所以妙真,我們執(zhí)行完請求之后,可以切換回主線程荚守,調(diào)用主線程的Looper對象去刷新UI珍德,這里要注意了练般,因為Handler會調(diào)用當(dāng)前線程的Looper對象,所以Handler需要在主線程中創(chuàng)建锈候,否則會報錯的薄料,所以總的來說,Handler更像一個切換線程的類
問題三:
如果我們非要在子線程中去刷新UI泵琳,也不是沒有辦法摄职,我們可以創(chuàng)建一個Looper,然后去獲取主線程的Looper對象即可获列,又或者可以在一個有Looper的線程中創(chuàng)建Handler也可以谷市,但是這樣就毫無意義了,所以總的來說击孩,當(dāng)我們需要使用Handler的時候迫悠,就在UI線程中去創(chuàng)建,我們來看看怎么獲取主線程的Looper對象和創(chuàng)建Looper對象
new Thread(new Runnable() {
@Override
public void run() {
//getMainLooper獲取主線程的Looper對象
Handler handler =new Handler(Looper.getMainLooper ());
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
//創(chuàng)建一個Looper對象
Looper.prepare();
Handler handler =new Handler();
//開啟消息循環(huán)
Looper.loop();
}
}).start();
好了巩梢,這就是Handler的機制创泄,今天是元宵,祝大家元宵節(jié)快樂@稹>弦帧!S瞩恕0稹H糁巍慨蓝!