介紹:
Handler機制指的是Android的消息機制,它的使用很簡單竖幔,通過它可以輕松的將一個任務(wù)切換到Handler所在的線程去執(zhí)行,我們用的最多的地方也就是Handler刷新UI的功能,其實,它還有很多用途敌完,比如子線程中進(jìn)行消耗的I/O操作羊初,讀取文件等滨溉,而我們用它來刷新UI,是因為子線程無法刷新UI长赞,可以通過它來切換回主線程執(zhí)行得哆,因此柳恐,本質(zhì)來說乐设,它只是常用來刷新UI而已
Handler機制
Handler機制也就是消息機制近尚,它與MessageQueue和Looper完成一個體系.
MessageQueue
從字面意思我們不難知道,它是個消息隊列戈锻,也就是說歼跟,它存儲了所有的消息,也可以叫它消息列表格遭,我們從Handler的sendMessage發(fā)出的消息都會被存儲到這里面
Looper
Looper翻譯成中文就是循環(huán)哈街,意思就是消息循環(huán),它會無限循環(huán)的從MessageQueue中讀取消息拒迅,如果有則處理骚秦,沒有就一直等待,MessageQueue雖然是消息隊列璧微,然而它并沒有能對消息進(jìn)行處理的操作作箍,因此,需要Looper的支持
Handler
Handler主要負(fù)責(zé)發(fā)送消息到MessageQueue前硫,它在創(chuàng)建的時候胞得,會采用當(dāng)前線程的Looper來構(gòu)成消息系統(tǒng),但是注意了屹电,線程默認(rèn)是沒有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)什么后果,后果就是我們達(dá)不到預(yù)期的UI控件刷新順序诗赌,我們可能想控件1先刷新控件2再刷新汗茄,有可能就會出現(xiàn)相反的順序,也可能同時刷新境肾,并且剔难,如果有N條子線程,線程并發(fā)問題會更嚴(yán)重奥喻,所以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對象