(七)App啓動流程第2篇函數
書接上文,App啓動一共有七個階段,上篇文章篇幅所限,咱們只看了第一階段,接下來說剩餘的六個階段,仍然是拿鬥魚App舉例子。oop
簡單回顧一下第一階段的流程,就是Launcher向AMS發送一個跨進程通訊,經過AMN/AMP,告訴AMS,我要啓動鬥魚App。插件
畫一個圖,描述一下啓動App所經歷的7個階段:線程
第2階段 AMS處理Launcher傳過來的信息代理
這個階段主要是Binder的Server端在作事情。由於咱們是沒有機會修改Binder的Server端邏輯的,因此這個階段看起來很是枯燥,我儘可能說的簡單些。對象
前面講過,Binder的雙方進行通訊是平等的,誰發消息,誰就是Client,接收的一方就是Server。Client這邊會調用Server的代理對象。blog
對於從Launcher發來的消息,經過AMS的代理對象AMP,發送給AMS。繼承
那麼當AMS想給Launcher發消息,又該怎麼辦呢?前面不是把Launcher以及它所在的進程給傳過來了嗎?它在AMS這邊保存爲一個ActivityRecord對象,這個對象裏面有一個ApplicationThreadProxy,單單從名字看就出賣了它,這就是一個Binder代理對象。它的Binder真身,也就是ApplicationThread。隊列
站在AIDL的角度,來畫這張圖,是這樣的:進程
因此結論是,AMS經過ApplicationThreadProxy發送消息,而App端則是經過ApplicationThread來接收這個消息。
第3階段 Launcher去休眠,而後通知AMS,我真的已經「停薪留職」了,沒有吃空餉
ApplicationThread(簡稱APT),它和ApplicationThreadProxy(簡稱ATP)的關係,咱們在第三階段已經介紹過了。
APT接收到來自AMS的消息後,就調用ActivityThread的sendMessage方法,向Launcher的主線程消息隊列發送一個PAUSE_ACTIVITY消息。
前面說過,ActivityThread就是主線程(UI線程)
看到下面的代碼是否是很親切?
發送消息是經過一個名爲H的Handler類的完成的,這個H類的名字真特麼有個性,想記不住都難。
作App的同窗都知道,繼承自Handler類的子類,就要實現handleMessage方法,這裏是一個switch…case語句,處理各類各樣的消息,PAUSE_ACTIVITY消息只是其中一種,由此也能預見到,AMS給Activity發送的全部消息,以及給其它三大組件發送的全部消息,都從H這裏通過,爲何要強調這一點呢,既然四大組件都走這條路,那麼這裏就能夠作點手腳,從而作插件化技術,這個咱們之後介紹插件化技術的時候會講到。
H對於PAUSE_ACTIVITY消息的處理,如上面的代碼,是調用ActivityThread的handlePauseActivity方法。這個方法幹兩件事:
你可能會找不到H和APT這兩個類文件,那是由於它們都是ActivityThread的內嵌類。
至此,Launcher的工做完成了。你能夠看到在這個過程當中,各個類都起到了什麼做用。芸芸衆生,粉墨登場:
第4階段 AMS啓動新的進程
接下來又輪到AMS作事了,大家會發現我不太喜歡講解AMS的流程,甚至都不畫UML圖,由於這部分邏輯和App開發人員關係不是很大,我儘可能說的簡單一些,把流程說清楚就好。
AMS接下來要啓動鬥魚App的首頁,由於鬥魚App不在後臺進程中,因此要啓動一個新的進程。這裏調用的是Process.start方法,而且指定了ActivityThread的main函數爲入口函數。
第5階段 新的進程啓動,以ActivityThread的main函數做爲入口
啓動新進程,其實就是啓動一個新的App。
在啓動新進程的時候,爲這個進程建立ActivityThread對象,這就是咱們耳熟能詳的主線程(UI線程)。
建立好UI線程後,馬上進入ActivityThread的main函數,接下來要作2件具備重大意義的事情:
1)建立一個主線程Looper,也就是MainLooper。看見沒,MainLooper就是在這裏建立的。
2)建立Application。記住,Application是在這裏生成的。
- - - - - - - - - - - - - -華麗的分割線 開始- - - - - - - - - - - - - - -
App開發人員對Application很是熟悉,由於咱們能夠在其中寫代碼,進行一些全局的控制,因此咱們一般認爲Application是掌控全局的,其實Application的地位在App中並無那麼重要,它就是一個Context上下文,僅此而已。
App中的靈魂是ActivityThread,也就是主線程,只是這個類對於App開發人員是訪問不到的——使用反射卻是能夠修改這個類的一些行爲。
- - - - - - - - - - - - - - -華麗的分割線 結束- - - - - - - - - - - - - - -
建立新App的最後,就是告訴AMS,我啓動好了,同時把本身的ActivityThread對象發送給AMS,今後之後,AMS的電話簿中就多了這個新的App的登記信息,AMS之後向這個App發送消息,就經過這個ActivityThread對象。
第6階段 AMS告訴新App啓動哪一個Activity
AMS把傳入的ActivityThread對象,轉爲一個ApplicationThread對象,用於之後和這個App跨進程通訊。還記得APT和ATP的關係嗎?這就又回到第2階段的那張關係圖了。
還記得第1階段,Launcher發送給AMS要啓動鬥魚App的哪一個Activity嗎?這個信息被AMS存下來了。
那麼在第6階段,AMS從過去的記錄中翻出來要啓動哪一個Activity,而後經過ATP告訴App。
第7階段 啓動鬥魚首頁Activity
畢其功於一役,盡在第7階段。這是最後一步。
App,這個Binder的另外一端,經過APT接收到AMS的消息,仍然是在H的handleMessage方法的switch語句中處理,只不過,此次消息的類型是LAUNCH_ACTIVITY:
ActivityClientRecord是什麼?這是AMS傳遞過來的要啓動的Activity。
仍是這裏,咱們仔細看那個getPackageInfoNoCheck方法,這個方法會提取Apk中的全部資源,而後設置給r的packageInfo屬性。這個屬性的類型頗有名,叫作LoadedApk。各位記住這裏,這個地方能夠幹壞事,也是插件化技術滲入的一個點。
在H的這個分支中,又反過來回調ActivityThread的handleLaunchActivity方法,你要是以爲很繞那就對了。其實我一直以爲,ActivityThread和H合併成一個類也沒問題。
從新看一下這個過程,每次都是APT執行ActivityThread的sendMessage方法,在這個方法中,把消息拼裝一下,而後扔個H的swicth語句去分析,來決定要執行ActivityThread的那個方法。每次都是這樣,習慣就行了。
handleLaunchActivity方法都作哪些事呢?
1)經過Instrumentation的newActivity方法,建立出來要啓動的Activity實例。
2)爲這個Activity建立一個上下文Context對象,並與Activity進行關聯。
3)經過Instrumentation的callActivityOnCreate方法,執行Activity的onCreate方法,從而啓動Activity。看到這裏是否是很熟悉很親切?
至此,App啓動完畢。這個流程是通過了不少次握手, App和ASM,頻繁的向對方發送消息,而發送消息的機制,是創建在Binder的基礎之上的。
下一篇文章,咱們講Context家族。