一响迂、什么是Handler
Handler 、 Looper 殃饿、Message 這三者都與Android異步消息處理線程相關(guān)的概念饮寞。那么什么叫異步消息處理線程呢?
異步消息處理線程啟動后會進入一個無限的循環(huán)體之中列吼,每循環(huán)一次幽崩,從其內(nèi)部的消息隊列中取出一個消息,然后回調(diào)相應(yīng)的消息處理函數(shù)寞钥,執(zhí)行完成一個消息后則繼續(xù)循環(huán)慌申。若消息隊列為空,線程則會阻塞等待理郑。
說了這一堆蹄溉,那么和Handler 、 Looper 您炉、Message有啥關(guān)系柒爵?其實Looper負(fù)責(zé)的就是創(chuàng)建一個MessageQueue,然后進入一個無限循環(huán)體不斷從該MessageQueue中讀取消息赚爵,而消息的創(chuàng)建者就是一個或多個Handler 棉胀。
二法瑟、handler的使用方法
1、handle.sendMessge
2唁奢、handler.post(runable)方法
handler.post()方法最終調(diào)用的還是sendMessage方法霎挟。
默認(rèn)創(chuàng)建了一個message對象。
可以看到麻掸,在getPostMessage中酥夭,得到了一個Message對象,然后將我們創(chuàng)建的Runable對象作為callback屬性脊奋,賦值給了此message.
注:產(chǎn)生一個Message對象熬北,可以new ?,也可以使用Message.obtain()方法狂魔;兩者都可以蒜埋,但是更建議使用obtain方法,因為Message內(nèi)部維護了一個Message池用于Message的復(fù)用最楷,避免使用new 重新分配內(nèi)存整份。
在dispatchMessage方法中,如果message.callback,這個callback就是上面的ranable對象籽孙,然后就是調(diào)用handleCallback()方法,執(zhí)行run方法烈评。
三、handler 機制的原理
Handle的構(gòu)造方法犯建,主要是或者一個Looper對象讲冠,線程的消息循環(huán)。
通過Looper.myLooper()獲取了當(dāng)前線程保存的Looper實例适瓦,然后在又獲取了這個Looper實例中保存的MessageQueue(消息隊列)竿开,這樣就保證了handler的實例與我們Looper實例中MessageQueue關(guān)聯(lián)上了。
隨后玻熙,我們會經(jīng)常調(diào)用sendMessage方法否彩,
public final boolean sendMessage(Message msg)
{
returnsendMessageDelayed(msg,0);
}
接著是sendMessageDelayed方法。
我們有來到了sendMessageAtTime方法嗦随,然后有調(diào)用enqueueMessage()方法列荔。
最后來了MessageQueue這個隊列中,執(zhí)行了quene.enqueueMessage()方法枚尼。也就是說handler發(fā)出的消息贴浙,最終會保存到消息隊列中去。
最后Looper的loop的方法中署恍,調(diào)用了handler.dispatchMessage崎溃,完成了消息發(fā)送。
ThreadLocal
實現(xiàn)一個線程本地的存儲锭汛,也就是說笨奠,每個線程都有自己的局部變量袭蝗。所有線程都共享一個ThreadLocal對象,但是每個線程在訪問這些變量的時候能得到不同的值般婆,每個線程可以更改這些變量并且不會影響其他的線程到腥,并且支持null值。
Looper
Looper用于封裝了android線程中的消息循環(huán)蔚袍,默認(rèn)情況下一個線程是不存在消息循環(huán)(message loop)的乡范,需要調(diào)用Looper.prepare()來給線程創(chuàng)建一個消息循環(huán),調(diào)用Looper.loop()來使消息循環(huán)起作用啤咽,從消息隊列里取消息晋辆,處理消息。
對于Looper主要是prepare()和loop()兩個方法宇整。
首先看prepare()方法
Looper.prepare()方法瓶佳,是為當(dāng)年線程設(shè)置一個Looper對象,使用ThreadLocal是保證每個線程的Looper是唯一的鳞青。其中Android主線程的Looper實在ActivityThread創(chuàng)建的時候就已經(jīng)創(chuàng)建霸饲,所以,我們使用Handle的時候臂拓,并沒有執(zhí)行Looper.prepaer方法厚脉。
sThreadLocal是一個ThreadLocal對象,可以在一個線程中存儲變量胶惰∩倒ぃ可以看到,將一個Looper的實例放入了ThreadLocal孵滞,判斷了sThreadLocal是否為null中捆,否則拋出異常。這也就說明了Looper.prepare()方法不能被調(diào)用兩次坊饶,同時也保證了一個線程中只有一個Looper實例~相信有些哥們一定遇到這個錯誤轨香。
在Looper的構(gòu)造方法中創(chuàng)建一個MessageQueue實例。
在Looper的loop方法 有一個阻塞時的消息循環(huán)幼东,只有要消息傳入,就會調(diào)用Handler.dispatchMessage();
其中?MessageQueue的核心方法科雳,next()方法就是從MessageQueue隊列中獲取信息根蟹。從源碼分析中可以看出
從上面的源碼中我們知道:隊列被激活之后,首先判斷隊首是不是消息屏障糟秘,如果是則跳過所有的同步消息简逮,查找最先要處理的異步消息。如果第一個待處理的消息還沒有到要處理的時機則設(shè)置激活等待時間尿赚;否則這個消息就是需要處理的消息散庶,將該消息設(shè)置為inuse蕉堰,并將隊列設(shè)置為非 blocked狀態(tài),然后返回該消息悲龟。next()方法是一個無線循環(huán)的方法屋讶,如果消息隊列中沒有消息,那么next()方法會一直阻塞须教,當(dāng)有新消息到來時皿渗,next會將這條消息返回同時也將這條消息從鏈表中刪除。
Looper主要作用:
1轻腺、與當(dāng)前線程綁定乐疆,保證一個線程只會有一個Looper實例,同時一個Looper實例也只有一個MessageQueue贬养。
2挤土、loop()方法,不斷從MessageQueue中去取消息误算,交給消息的target屬性的dispatchMessage去處理仰美。
好了,我們的異步消息處理線程已經(jīng)有了消息隊列(MessageQueue)尉桩,也有了在無限循環(huán)體中取出消息的哥們筒占,現(xiàn)在缺的就是發(fā)送消息的對象了,于是乎:Handler登場了蜘犁。
四翰苫、handler 引起的內(nèi)存泄漏以及解決方法
參考文獻(xiàn)
Android 異步消息處理機制 讓你深入理解 Looper、Handler这橙、Message三者關(guān)系