作者簡(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》