Android消息機(jī)制源碼分析

作者簡(jiǎn)介? 原創(chuàng)微信公眾號(hào)郭霖 WeChat ID: guolin_blog

本篇是小楠的第二篇投稿寝优,從源碼的角度分析了Handler機(jī)制,因?yàn)樯婕霸创a,內(nèi)容還是挺多的探熔,需要花費(fèi)一些時(shí)間來(lái)閱讀理解了。最后烘挫,希望對(duì)大家有所幫助诀艰。

小楠的博客地址:

http://www.reibang.com/u/70c12759d4fe

前言

很多讀者,尤其是初學(xué)者特別抗拒去看源碼饮六,這里我說(shuō)明一下為什么要進(jìn)行源碼分析其垄。其中包括下面一些好處:

學(xué)習(xí)Android源碼有助于我們學(xué)習(xí)其中的設(shè)計(jì)模式、思想卤橄、架構(gòu)绿满。

熟悉整個(gè)源碼的架構(gòu),有助于我們更加正確地調(diào)用Android提供的SDK窟扑,寫(xiě)出高效正確的代碼喇颁。

學(xué)習(xí)源碼有助于我們面試漏健,因?yàn)榇蠊径枷矚g問(wèn)這些。

學(xué)習(xí)源碼有助于我們學(xué)習(xí)一些黑科技橘霎,比如學(xué)習(xí)插件化的從時(shí)候我們需要學(xué)習(xí)Hook機(jī)制蔫浆,但是學(xué)習(xí)Hook機(jī)制的時(shí)候我們需要掌握Activity的啟動(dòng)流程、消息機(jī)制等等機(jī)制姐叁。

我個(gè)人覺(jué)得瓦盛,只懂得去調(diào)用API,跟掌握API底層的實(shí)現(xiàn)外潜,這是一個(gè)碼農(nóng)跟高級(jí)工程師的區(qū)別原环。只會(huì)用API每天只能做很多重復(fù)性的工作,但是學(xué)習(xí)了源碼以后处窥,我們能夠做到很多原生API做不到的事情嘱吗,這就是我們所說(shuō)的黑科技,這樣能夠讓我們的知識(shí)面更加廣泛碧库,因?yàn)楣裼耄词挂粋€(gè)人天資再好也罷,如果他的見(jiàn)識(shí)面不夠廣泛嵌灰,很多東西(比如說(shuō)熱更新弄匕、插件化、NDK)沒(méi)有接觸過(guò)的話(huà)沽瞭,永遠(yuǎn)只能停留在他所到達(dá)的瓶頸上面迁匠。

對(duì)于像本人一樣在做系統(tǒng)APP、系統(tǒng)Framework層開(kāi)發(fā)和定制來(lái)說(shuō)源碼可能比較重要驹溃,但是這并不意味著做第三方APP的時(shí)候就不重要城丧。當(dāng)然,學(xué)習(xí)源碼需要有一定的耐心豌鹤,也可能需要你在分析的過(guò)程中去畫(huà)一些圖(圖片更加直觀(guān))亡哄、花額外的時(shí)間去學(xué)習(xí)源碼用到的設(shè)計(jì)模式等等,學(xué)習(xí)源碼是一個(gè)比較痛苦的事情布疙,因?yàn)槟銜?huì)發(fā)現(xiàn)掌握了源碼并不意味者你就能夠一步登天蚊惯。但是隨著親們慢慢地掌握了整個(gè)Android的系統(tǒng)架構(gòu)的時(shí)候,相信你不會(huì)后悔當(dāng)初自己的付出灵临。因?yàn)槲乙恢倍枷嘈沤匦停冻霰囟〞?huì)有所收獲。

這里扯個(gè)題外話(huà)儒溉,剛剛提到NDK宦焦,我覺(jué)得NDK也是一塊比較重要的模塊,它能夠利用C/C++來(lái)實(shí)現(xiàn)Java實(shí)現(xiàn)不了,或者用Java去實(shí)現(xiàn)的時(shí)候效率很低的事情波闹,比如說(shuō)QQ的變聲功能酝豪、全民K歌的音頻混合、視頻處理精堕、直播等等寓调,所以有時(shí)間的話(huà)我將會(huì)寫(xiě)一些關(guān)于NDK的文章。

應(yīng)用程序的入口分析

應(yīng)用程序的入口是 在A(yíng)ctivityThread 的 main 方法中的(當(dāng)應(yīng)用程序啟動(dòng)的時(shí)候锄码,會(huì)通過(guò)底層的C/C++去調(diào)用main方法),這個(gè)方法在 ActivityThread類(lèi) 的最后一個(gè)函數(shù)里面晌涕,核心代碼如下:

在分析源碼的時(shí)候滋捶,你可能會(huì)發(fā)現(xiàn)一些 if(false){} 之類(lèi)的語(yǔ)句,這種寫(xiě)法是方便調(diào)試的余黎,通過(guò)一個(gè)標(biāo)志就可以控制某些代碼是否執(zhí)行重窟,比如說(shuō)是否輸出一些系統(tǒng)的Log。

在 main 方法里面惧财,首先初始化了我們的 Environment對(duì)象巡扇,然后創(chuàng)建了 Looper,然后開(kāi)啟消息循環(huán)垮衷。根據(jù)我們的常識(shí)知道厅翔,如果程序沒(méi)有死循環(huán)的話(huà),執(zhí)行完 main函數(shù)(比如構(gòu)建視圖等等代碼)以后就會(huì)立馬退出了搀突。之所以我們的APP能夠一直運(yùn)行著刀闷,就是因?yàn)?Looper.loop() 里面是一個(gè)死循環(huán):

publicstaticvoidloop() {

for(;;) { ? ?}}

這里有一個(gè)小小的知識(shí),就是之所以用 for (;;) 而不是用 while(true) 是因?yàn)榉乐挂恍┤送ㄟ^(guò)黑科技去修改這個(gè)循環(huán)的標(biāo)志(比如通過(guò)反射的方式)

在非主線(xiàn)程里面我們也可以搞一個(gè) Handler仰迁,但是需要我們主動(dòng)去為當(dāng)前的子線(xiàn)程綁定一個(gè) Looper甸昏,并且啟動(dòng)消息循環(huán)。

Looper 主要有兩個(gè)核心的方法徐许,一是 prepare施蜜,而是開(kāi)始 loop 循環(huán)。通過(guò) Looper雌隅、Handler翻默、Message、MessageQueue 等組成了 Android 的消息處理機(jī)制澄步,也叫事件冰蘑、反饋機(jī)制。

為什么需要這樣一個(gè)消息機(jī)制

我們知道每一個(gè)應(yīng)用程序都有一個(gè)主線(xiàn)程村缸,主線(xiàn)程一直循環(huán)的話(huà)祠肥,那么我們的自己的代碼就無(wú)法執(zhí)行了。而系統(tǒng)在主線(xiàn)程綁定一個(gè) Looper 循環(huán)器以及消息隊(duì)列,Looper 就像是一個(gè)水泵一樣不斷把消息發(fā)送到主線(xiàn)程仇箱。如果沒(méi)有消息機(jī)制县恕,我們的代碼需要直接與主線(xiàn)程進(jìn)行訪(fǎng)問(wèn),操作剂桥,切換忠烛,訪(fǎng)問(wèn)主線(xiàn)程的變量等等,這樣做會(huì)帶來(lái)不安全的問(wèn)題权逗,另外APP的開(kāi)發(fā)的難度也會(huì)提高美尸,同時(shí)也不利于整個(gè) Android 系統(tǒng)的運(yùn)作。有了消息機(jī)制斟薇,我們可以簡(jiǎn)單地通過(guò)發(fā)送消息师坎,然后 Looper 把消息發(fā)送到主線(xiàn)程,然后就可以執(zhí)行了堪滨。

消息其中包括:

我們自己的操作消息(客戶(hù)端的 Handler)

系統(tǒng)的操作消息(系統(tǒng) Handler):比如啟動(dòng) Activity 等四大組件(例如突然來(lái)電話(huà)的時(shí)候跳轉(zhuǎn)到電話(huà)界面)

我們的思路是先分析系統(tǒng)的 Handler胯陋,然后再去深入理解消息機(jī)制里面各個(gè)部件。

主線(xiàn)程與Looper的關(guān)系

舉個(gè)例子袱箱,廣播:AMS 發(fā)送消息到 MessageQueue遏乔,然后 Looper 循環(huán),系統(tǒng)的 Handler 取出來(lái)以后才處理发笔。(AMS 是處理四大組件的生命周期的一個(gè)比較重要的類(lèi)盟萨,在以后我們分析IPC機(jī)制以及Activity啟動(dòng)流程的時(shí)候會(huì)提到)

系統(tǒng)的Handler在哪里

在 ActivityThread 的成員變量里面有一個(gè)這樣的 大H(繼承Handler),這個(gè)就是系統(tǒng)的Handler:

finalHmH=newH();

回顧一下 ActivityThread 的 main 方法可以知道了讨,在 new ActivityThread 的時(shí)候鸯旁,系統(tǒng)的 Handler 就就初始化了,這是一種餓加載的方法量蕊,也就是在類(lèi)被new的時(shí)候就初始化成員變量了铺罢。另外還有一種懶加載,就是在需要的時(shí)候才去初始化残炮,這兩種方式在單例設(shè)計(jì)模式里面比較常見(jiàn)韭赘。

下面看系統(tǒng) Handler 的定義(下方高能,看的時(shí)候可以跳過(guò)一些case势就,粗略地看即可):

從系統(tǒng)的 Handler 中泉瞻,在 handleMessage 我們可以看到很多關(guān)于四大組件的生命周期操作,比如創(chuàng)建苞冯、銷(xiāo)毀袖牙、切換、跨進(jìn)程通信舅锄,也包括了整個(gè)Application進(jìn)程的銷(xiāo)毀等等鞭达。

比如說(shuō)我們有一個(gè) 應(yīng)用程序A 通過(guò) Binder 去跨進(jìn)程啟動(dòng)另外一個(gè) 應(yīng)用程序B 的 Service(或者同一個(gè)應(yīng)用程序中不同進(jìn)程的Service),如圖:

跨進(jìn)程啟動(dòng)Service

最后是 AMS 接收到消息以后,發(fā)送消息到 MessageQueue 里面畴蹭,最后由系統(tǒng)的 Handler 處理啟動(dòng) Service 的操作:

在 handleCreateService 里通過(guò)反射的方式去 newInstance()坦仍,并且回調(diào)了 Service 的 onCreate方法:

又例如我們可以通過(guò)發(fā)SUICIDE消息可以自殺,這樣來(lái)退出應(yīng)用程序叨襟。

caseSUICIDE:Process.killProcess(Process.myPid());

break;

應(yīng)用程序的退出過(guò)程

實(shí)際上我們要退出應(yīng)用程序的話(huà)繁扎,就是讓主線(xiàn)程結(jié)束,換句話(huà)說(shuō)就是要讓 Looper 的循環(huán)結(jié)束糊闽。這里是直接結(jié)束 Looper 循環(huán)梳玫,因此我們四大組件的生命周期方法可能就不會(huì)執(zhí)行了,因?yàn)樗拇蠼M件的生命周期方法就是通過(guò) Handler 去處理的右犹,Looper 循環(huán)都沒(méi)有了汽纠,四大組件還玩毛線(xiàn)!因此我們平常寫(xiě)程序的時(shí)候就要注意了傀履,onDestroy 方法是不一定能夠回調(diào)的。

這里實(shí)際上是調(diào)用了 MessageQueue 的 quit莉炉,清空所有 Message钓账。

publicvoidquit() { ? ?mQueue.quit(false);}

tips:看源碼一定不要慌,也不要一行一行看絮宁,要抓住核心的思路去看即可梆暮。

消息機(jī)制的分析

消息對(duì)象Message的分析

提到消息機(jī)制,在 MessageQueue 里面存在的就是我們的 Message對(duì)象:

首先我們可以看到 Message 對(duì)象是實(shí)現(xiàn)了 Parcelable 接口的绍昂,因?yàn)?Message 消息可能需要跨進(jìn)程通信啦粹,這時(shí)候就需要進(jìn)程序列化以及反序列化操作了。

Message 里面有一些我們常見(jiàn)的參數(shù)窘游,arg1 arg2 obj callback when 等等唠椭。這里要提一下的就是這個(gè) target 對(duì)象,這個(gè)對(duì)象就是發(fā)送這個(gè)消息的 Handler對(duì)象忍饰,最終這條消息也是通過(guò)這個(gè) Handler 去處理掉的贪嫂。

Message Pool消息池的概念——重復(fù)利用Message

Message里面中一個(gè)非常重要的概念,就是消息池Pool:

我們通過(guò)obtain方法取出一條消息的時(shí)候艾蓝,如果發(fā)現(xiàn)當(dāng)前的消息池不為空力崇,那就直接重復(fù)利用Message(已經(jīng)被創(chuàng)建過(guò)和handle過(guò)的);如果為空就重新 new 一個(gè)消息赢织。這就是一種享元設(shè)計(jì)模式的概念亮靴。例如在游戲里面,發(fā)子彈于置,如果一個(gè)子彈是一個(gè)對(duì)象茧吊,一按下按鍵就發(fā)很多個(gè)子彈,那么這時(shí)候就需要利用享元模式去循環(huán)利用了。

這個(gè)消息池是通過(guò)鏈表的實(shí)現(xiàn)的饱狂,通過(guò)上面的代碼可以知道曹步,sPool永遠(yuǎn)指向這個(gè)消息池的頭,取消息的時(shí)候休讳,先拿到當(dāng)前的頭sPool讲婚,然后使得sPool指向下一個(gè)結(jié)點(diǎn),最后返回剛剛?cè)〕鰜?lái)的結(jié)點(diǎn)俊柔,如下圖所示:

上面我們知道了消息可以直接創(chuàng)建筹麸,也可以通過(guò)obtain方法循環(huán)利用。所以我們平常編程的時(shí)候就要養(yǎng)成好的習(xí)慣雏婶,循環(huán)利用物赶。

消息的回收機(jī)制

有消息的創(chuàng)建,必然有回收利用留晚,下面兩個(gè)是Message的回收相關(guān)的核心方法:

recycleUnchecked 中拿到消息池酵紫,清空當(dāng)前的消息,next 指向當(dāng)前的頭指針错维,頭指針指向當(dāng)前的 Message對(duì)象奖地,也就是在消息池頭部插入當(dāng)前的消息。

關(guān)于消息的回收還有一點(diǎn)需要注意的就是赋焕,我們平時(shí)寫(xiě) Handler 的時(shí)候不需要我們手動(dòng)回收参歹,因?yàn)楣雀璧墓こ處熞呀?jīng)有考慮到這方面的問(wèn)題了。消息是在 Handler 分發(fā)處理之后就會(huì)被自動(dòng)回收的隆判,我們回到 Looper 的 loop方法 里面:

msg.target.dispatchMessage(msg) 就是處理消息犬庇,緊接著在 loop方法 的最后調(diào)用了msg.recycleUnchecked() 這就是回收了 Message。

消息的循環(huán)過(guò)程分析

下面我們繼續(xù)分析這個(gè)死循環(huán):

1侨嘀、首先拿到 Looper 對(duì)象(me)臭挽,如果當(dāng)前的線(xiàn)程沒(méi)有 Looper,那么就會(huì)拋出異常咬腕,這就是為什么在子線(xiàn)程里面創(chuàng)建Handler如果不手動(dòng)創(chuàng)建和啟動(dòng) Looper 會(huì)報(bào)錯(cuò)的原因埋哟。

2、然后拿到 Looper 的成員變量 MessageQueue郎汪,在 MessageQueue 里面不斷地去取消息赤赊,關(guān)于 MessageQueue 的 next方法 如下:

這里可以看到消息的取出用到了一些native方法,這樣做是為了獲得更高的效率煞赢,消息的去取出并不是直接就從隊(duì)列的頭部取出的抛计,而是根據(jù)了消息的when時(shí)間參數(shù)有關(guān)的,因?yàn)槲覀兛梢园l(fā)送延時(shí)消息照筑、也可以發(fā)送一個(gè)指定時(shí)間點(diǎn)的消息吹截。因此這個(gè)函數(shù)有點(diǎn)復(fù)雜瘦陈,我們點(diǎn)到為止即可。

3波俄、繼續(xù)分析 loop方法:如果已經(jīng)沒(méi)有消息了晨逝,那么就可以退出循環(huán),那么整個(gè)應(yīng)用程序就退出了懦铺。什么情況下會(huì)發(fā)生呢捉貌?還記得我們分析應(yīng)用退出嗎?

在 系統(tǒng)Handler 收到 EXIT_APPLICATION 消息的時(shí)候冬念,就會(huì)調(diào)用 Looper 的 quit方法:

Looper 的 quit方法 如下趁窃,實(shí)際上就是調(diào)用了消息隊(duì)列的 quit方法:

publicvoidquit() { ? ?mQueue.quit(false);}

而消息隊(duì)列的 quit方法 實(shí)際上就是執(zhí)行了消息的清空操作,然后在 Looper 循環(huán)里面如果取出消息為空的時(shí)候急前,程序就退出了:

removeAllFutureMessagesLocked 方法如下:

4醒陆、msg.target.dispatchMessage(msg)就是處理消息,這里就會(huì)調(diào)用Handler的dispatchMessage方法:

在這個(gè)方法里面會(huì)先去判斷 Message 的 callback 是否為空裆针,這個(gè) callback 是在 Message類(lèi) 里面定義的:

Runnablecallback;

這是一個(gè) Runnable對(duì)象刨摩,handleCallback方法 里面做的事情就是拿到這個(gè) Runnable 對(duì)象,然后在 Handler 所創(chuàng)建的線(xiàn)程(例如主線(xiàn)程)執(zhí)行run方法:

Handler(Looper)在哪個(gè)線(xiàn)程創(chuàng)建的世吨,就在哪個(gè)線(xiàn)程回調(diào)澡刹,沒(méi)毛病,哈哈另假!

這就是我們平常使用post系列的方法:post、postAtFrontOfQueue怕犁、postAtTime边篮、postDelayed。其實(shí)最終也是通過(guò)Message包裝一個(gè)Runnable實(shí)現(xiàn)的奏甫,我們看其中一個(gè)即可:

通過(guò) post 一個(gè)Runnable的方式我們可以很簡(jiǎn)單地做一個(gè)循環(huán)戈轿,比如無(wú)限輪播的廣告條Banner:

當(dāng)然,我們的 Handler 自己也可以有一個(gè) mCallback 對(duì)象:

如果自身的 Callback 不為空的話(huà)阵子,就會(huì)回調(diào) Callback 的方法思杯。例如我們創(chuàng)建 Handler 的時(shí)候可以帶上 Callback:

如果自身的 Callback 執(zhí)行之后沒(méi)有返回 true(沒(méi)有攔截),那么最后才會(huì)回調(diào)我們經(jīng)常需要復(fù)寫(xiě)的 handleMessage 方法挠进,這個(gè)方法的默認(rèn)實(shí)現(xiàn)是空處理:

publicvoidhandleMessage(Messagemsg) {}

5色乾、最后是回收消息:msg.recycleUnchecked()。所以說(shuō):我們平時(shí)在處理完handleMessage之后并不需要我們程序員手動(dòng)去進(jìn)行回收哈领突!系統(tǒng)已經(jīng)幫我們做了這一步操作了暖璧。

6、通過(guò)上面就完成了一次消息的循環(huán)君旦。

消息的發(fā)送

分析完消息的分發(fā)與處理澎办,最后我們來(lái)看看消息的發(fā)送:

消息的發(fā)送有這一系列方法嘲碱,甚至我們的一系列post方法(封裝了帶Runnable的Message),最終都是調(diào)用sendMessageAtTime方法局蚀,把消息放到消息隊(duì)列里面:

MessageQueue的進(jìn)入隊(duì)列的方法如下掉缺,核心思想就是時(shí)間比較小的(越是需要馬上執(zhí)行的消息)就越防到越靠近頭指針的位置:

消息并不是一直在隊(duì)列的尾部添加的宪祥,而是可以指定時(shí)間,如果是立馬需要執(zhí)行的消息,就會(huì)插到隊(duì)列的頭部绊汹,就會(huì)立馬處理,如此類(lèi)推耗溜。

關(guān)于這一點(diǎn)這里我們可以從MessageQueue的next方法知道痴鳄,next是考慮消息的時(shí)間when變量的,下面回顧一下MessageQueue的next方法里面的一些核心代碼:next方法并不是直接從頭部取出來(lái)的县貌,而是會(huì)去遍歷所有消息术陶,根據(jù)時(shí)間戳參數(shù)等信息來(lái)取消息的。

線(xiàn)程與Looper的綁定

線(xiàn)程里面默認(rèn)情況下是沒(méi)有 Looper 循環(huán)器的煤痕,因此我們需要調(diào)用 prepare方法 來(lái)關(guān)聯(lián)線(xiàn)程和 Looper:

此處調(diào)用了?ThreadLocal 的 set方法梧宫,并且 new 了一個(gè) Looper 放進(jìn)去。

可以看到 Looper 與線(xiàn)程的關(guān)聯(lián)是通過(guò) ThreadLocal 來(lái)進(jìn)行的摆碉,如下圖所示:

ThreadLocal 是JDK提供的一個(gè)解決線(xiàn)程不安全的類(lèi)塘匣,線(xiàn)程不安全問(wèn)題歸根結(jié)底主要涉及到變量的多線(xiàn)程訪(fǎng)問(wèn)問(wèn)題,例如變量的臨界問(wèn)題巷帝、值錯(cuò)誤忌卤、并發(fā)問(wèn)題等。這里利用ThreadLocal 綁定了 Looper 以及線(xiàn)程楞泼,就可以避免其他線(xiàn)程去訪(fǎng)問(wèn)當(dāng)前線(xiàn)程的 Looper 了驰徊。

ThreadLocal 通過(guò) get 以及 set方法 就可以綁定線(xiàn)程和 Looper 了,這里只需要傳入 Value 即可堕阔,因?yàn)榫€(xiàn)是可以通過(guò) Thread.currentThread() 去拿到的:

為什么可以綁定線(xiàn)程了呢棍厂?

map.set(this, value) 通過(guò)把自身(ThreadLocal以及值(Looper)放到了一個(gè)Map里面,如果再放一個(gè)的話(huà)超陆,就會(huì)覆蓋牺弹,因?yàn)閙ap不允許鍵值對(duì)中的鍵是重復(fù)的)

因此ThreadLocal綁定了線(xiàn)程以及Looper。

因?yàn)檫@里實(shí)際上把變量(這里是指Looper)放到了Thread一個(gè)成員變量Map里面时呀,關(guān)鍵的代碼如下:

ThreadLocal的getMap方法實(shí)際上是拿到線(xiàn)程的MAP张漂,底層是通過(guò)數(shù)組(實(shí)際上數(shù)據(jù)結(jié)構(gòu)是一種散列列表)實(shí)現(xiàn)的,具體的實(shí)現(xiàn)就點(diǎn)到為止了谨娜。

如果android系統(tǒng)主線(xiàn)程Looper可以隨隨便便被其他線(xiàn)程訪(fǎng)問(wèn)到的話(huà)就會(huì)很麻煩了鹃锈,啊哈哈,你懂的瞧预。

Handler屎债、Looper是怎么關(guān)聯(lián)起來(lái)的呢仅政?

我們知道,Looper是與線(xiàn)程相關(guān)聯(lián)的(通過(guò)ThreadLocal)盆驹,而我們平常使用的Handler是這樣的:

其實(shí) Handler 在構(gòu)造的時(shí)候圆丹,有多個(gè)重載方法,根據(jù)調(diào)用關(guān)系鏈躯喇,所以最終會(huì)調(diào)用下面這個(gè)構(gòu)造方法:

這里只給出了核心的代碼辫封,可以看到我們?cè)跇?gòu)造Handler的時(shí)候,是通過(guò)Looper的靜態(tài)方法myLooper()去拿到一個(gè)Looper對(duì)象的:

看廉丽,我們的又出現(xiàn)了ThreadLocal倦微,這里就是通過(guò)ThreadLocal的get方法去拿到當(dāng)前線(xiàn)程的Looper,因此Handler就跟線(xiàn)程綁定在一起了正压,在一起欣福,在一起,啊哈哈焦履。

一般們是在A(yíng)ctivity里面使用Handler的拓劝,而Activity的生命周期是在主線(xiàn)程回調(diào)的,因此我們一般使用的Handler是跟主線(xiàn)程綁定在一起的嘉裤。

主線(xiàn)程一直在循環(huán)郑临,為什么沒(méi)有卡死,還能響應(yīng)我們的點(diǎn)擊之類(lèi)的呢屑宠?

通過(guò)子線(xiàn)程去訪(fǎng)問(wèn)主線(xiàn)程的代碼厢洞,有代碼注入、回調(diào)機(jī)制嘛典奉。

切入到消息隊(duì)列里面的消息去訪(fǎng)問(wèn)主線(xiàn)程躺翻,例如傳消息,然后回調(diào)四大組件的生命周期等等秋柄。

IPC跨進(jìn)程的方式也可以實(shí)現(xiàn)获枝。

雖然主線(xiàn)程一直在執(zhí)行蠢正,但是我們可以通過(guò)外部條件骇笔、注入的方法來(lái)執(zhí)行自己的代碼,而不是一直死循環(huán)嚣崭。

總結(jié)

如圖所示笨触,在主線(xiàn)程ActivityThread中的main方法入口中,先是創(chuàng)建了系統(tǒng)的Handler(H)雹舀,創(chuàng)建主線(xiàn)程的Looper芦劣,將Looper與主線(xiàn)程綁定,調(diào)用了Looper的loop方法之后開(kāi)啟整個(gè)應(yīng)用程序的主循環(huán)说榆。Looper里面有一個(gè)消息隊(duì)列虚吟,通過(guò)Handler發(fā)送消息到消息隊(duì)列里面寸认,然后通過(guò)Looper不斷去循環(huán)取出消息,交給Handler去處理串慰。通過(guò)系統(tǒng)的Handler偏塞,或者說(shuō)Android的消息處理機(jī)制就確保了整個(gè)Android系統(tǒng)有條不紊地運(yùn)作,這是Android系統(tǒng)里面的一個(gè)比較重要的機(jī)制邦鲫。

我們的APP也可以創(chuàng)建自己的Handler灸叼,可以是在主線(xiàn)程里面創(chuàng)建,也可以在子線(xiàn)程里面創(chuàng)建庆捺,但是需要手動(dòng)創(chuàng)建子線(xiàn)程的Looper并且手動(dòng)啟動(dòng)消息循環(huán)古今。

花了一天的時(shí)間,整個(gè)Android消息機(jī)制源碼分析就到這里結(jié)束了滔以,今天的天氣真不錯(cuò)捉腥,但是我選擇了在自己的房間學(xué)習(xí)Android的消息機(jī)制,我永遠(yuǎn)相信醉者,付出總會(huì)有所收獲的但狭!


文章原創(chuàng)作者GuoLin 書(shū)籍推薦

郭林大神原創(chuàng)android 書(shū)籍:《第一行代碼 android》

淘寶鏈接:

https://s.click.taobao.com/t?e=m%3D2%26s%3DgKUfuKdAZKocQipKwQzePOeEDrYVVa64K7Vc7tFgwiHjf2vlNIV67p2n%2BQBNMyE6Rku8%2Bpj6eJall3bs%2B3NRhNHnsKI%2BqxhyM0iVZhTFBom4YIorMPnmg8G0g2OJi%2FzmXHfenomYtn5EW9vzeG8LzfPUwktUBEmkxg5p7bh%2BFbQ%3D&pvid=10_106.6.161.154_3367_1490163222155

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市撬即,隨后出現(xiàn)的幾起案子立磁,更是在濱河造成了極大的恐慌,老刑警劉巖剥槐,帶你破解...
    沈念sama閱讀 206,723評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件唱歧,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡粒竖,警方通過(guò)查閱死者的電腦和手機(jī)颅崩,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,485評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)蕊苗,“玉大人沿后,你說(shuō)我怎么就攤上這事⌒嗯椋” “怎么了尖滚?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,998評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀(guān)的道長(zhǎng)瞧柔。 經(jīng)常有香客問(wèn)我漆弄,道長(zhǎng),這世上最難降的妖魔是什么造锅? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,323評(píng)論 1 279
  • 正文 為了忘掉前任撼唾,我火速辦了婚禮,結(jié)果婚禮上哥蔚,老公的妹妹穿的比我還像新娘倒谷。我一直安慰自己蛛蒙,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,355評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布渤愁。 她就那樣靜靜地躺著宇驾,像睡著了一般。 火紅的嫁衣襯著肌膚如雪猴伶。 梳的紋絲不亂的頭發(fā)上课舍,一...
    開(kāi)封第一講書(shū)人閱讀 49,079評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音他挎,去河邊找鬼筝尾。 笑死,一個(gè)胖子當(dāng)著我的面吹牛办桨,可吹牛的內(nèi)容都是我干的筹淫。 我是一名探鬼主播,決...
    沈念sama閱讀 38,389評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼呢撞,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼损姜!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起殊霞,我...
    開(kāi)封第一講書(shū)人閱讀 37,019評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤摧阅,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后绷蹲,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體棒卷,經(jīng)...
    沈念sama閱讀 43,519評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,971評(píng)論 2 325
  • 正文 我和宋清朗相戀三年祝钢,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了比规。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,100評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡拦英,死狀恐怖蜒什,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情疤估,我是刑警寧澤灾常,帶...
    沈念sama閱讀 33,738評(píng)論 4 324
  • 正文 年R本政府宣布,位于F島的核電站做裙,受9級(jí)特大地震影響岗憋,放射性物質(zhì)發(fā)生泄漏肃晚。R本人自食惡果不足惜锚贱,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,293評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望关串。 院中可真熱鬧拧廊,春花似錦监徘、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,289評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至倦春,卻和暖如春户敬,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背睁本。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,517評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工尿庐, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人呢堰。 一個(gè)月前我還...
    沈念sama閱讀 45,547評(píng)論 2 354
  • 正文 我出身青樓抄瑟,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親枉疼。 傳聞我的和親對(duì)象是個(gè)殘疾皇子皮假,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,834評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容