時(shí)光飛逝,不知不覺(jué)寫(xiě)完Handler系列文章已經(jīng)用時(shí)一個(gè)月了。作為我開(kāi)始分析Android Framework源碼的敲門(mén)磚還是遇到了很多挫折,尤其是分析MessageQueue源碼時(shí)那種百思不得其解的疑惑困擾著我很長(zhǎng)時(shí)間。不過(guò)當(dāng)我想通了這其中的原理后那種酣暢淋漓的感覺(jué)也讓我很有成就感。
Message緩存池
Android 的工程師們充分利用了Java的高級(jí)語(yǔ)言特性,即類中持有著一個(gè)類自身的屬性作為經(jīng)典數(shù)據(jù)結(jié)構(gòu)中的鏈表next指針,以靜態(tài)屬性屬于類本身的特性實(shí)現(xiàn)了鏈表的表頭。這種模式給我了很大的啟發(fā),讓我這種渣渣每逢想起都會(huì)驚訝“還有這種操作?”。
為什么要有緩存池
了解完Handler整體機(jī)制后我猜測(cè),Message功能十分單一且狀態(tài)很少,它只是一個(gè)具體發(fā)送消息的載體,但是使用數(shù)量十分龐大,回收用過(guò)的Message不僅可以有效的減少重復(fù)消耗系統(tǒng)資源且回收它的成本很低,所以何樂(lè)而不為呢?
誰(shuí)負(fù)責(zé)回收Message
我們使用Message時(shí)候知道調(diào)用Message.obtain();方法可以從緩存池中取出一個(gè)Message,有存才能有取,我們什么時(shí)候回收它呢?從源碼中發(fā)現(xiàn),Looper在分發(fā)Message給宿主Handler之后,確定了Message已經(jīng)完成了它的使命直接就會(huì)將它回收。所以我們完全不用擔(dān)心這個(gè),我們發(fā)送的每個(gè)消息最后都會(huì)被回收。
真正的阻塞發(fā)生在MessageQueue
MessageQueue維持的消息隊(duì)列也是靠跟Message緩存池同樣的原理生成的,每次消息出隊(duì)時(shí)如果沒(méi)有合適的待取出消息就會(huì)阻塞線程等待有合適的消息。
非常奇怪的是,MessageQueue線程的方式不是傳統(tǒng)使用java實(shí)現(xiàn)的,而是通過(guò)JNI調(diào)用native層的C++代碼實(shí)現(xiàn)的,C++代碼中也實(shí)現(xiàn)了一套Looper+MessageQueue+Handler,阻塞線程的方式是調(diào)用Linux的監(jiān)聽(tīng)文件描述符ePoll實(shí)現(xiàn)的。
我的猜測(cè)是因?yàn)镴ava代碼需要經(jīng)過(guò)JVM的幫助才能跟系統(tǒng)接觸,這一過(guò)程會(huì)消耗性能,而C++代碼則直接可以繞過(guò)這一個(gè)環(huán)節(jié)。所以,使用C++代碼實(shí)現(xiàn)線程阻塞可能是性能上的需求。
為什么推薦使用Handler實(shí)現(xiàn)線程間通信
在沒(méi)有真正了解Handler的時(shí)候以為Google的工程師們?cè)贖andler上使用了什么了不起的技術(shù)呢,所以才推薦開(kāi)發(fā)者們使用Handler來(lái)實(shí)現(xiàn)線程間通信。
其實(shí)呢?Android是事件型驅(qū)動(dòng)的系統(tǒng),剛創(chuàng)建一個(gè)應(yīng)用程序的主線程里就會(huì)被創(chuàng)建一個(gè)Looper來(lái)不斷接受各種事件,所以說(shuō)如果我們打開(kāi)一個(gè)程序什么都不操作,這個(gè)程序就有可能是阻塞狀態(tài)的,因?yàn)樗麤](méi)有任何事件需要去處理。反之,我們?cè)谧约旱腢I線程里執(zhí)行一項(xiàng)耗時(shí)操作,主線程Looper一直在處理這個(gè)任務(wù)而無(wú)法分身處理其它的事件這時(shí)候就有可能ANR了。
所以,不是Handler的技術(shù)多牛逼,是主線程用了Handler來(lái)通信,你是用別的方法通信有可能會(huì)影響主線程Looper的正常工作。