這篇文章講解當用戶點擊應(yīng)用圖標時殖卑,安卓如何啟動你的應(yīng)用醉拓。安卓系統(tǒng)做了很多幕后工作灶体,來使得你的launch activity對用戶可見嫉父。本文通過重要階段的講解和調(diào)用序列詳細講解這一過程盯荤。
安卓應(yīng)用在這兩個方面是獨特的:
多個入口點:Android應(yīng)用程序由不同的組件組成,它們可以調(diào)用其他應(yīng)用程序擁有的組件彪见。這些組件大致對應(yīng)于任何應(yīng)用程序的多個入口點丘薛。因此,它們不同于具有像main()方法那樣的單個入口點的傳統(tǒng)應(yīng)用程序睦柴。
擁有自己的小世界:每個Android應(yīng)用程序都生活在自己的世界中诽凌,它在單獨的進程中運行,擁有自己的Dalvik VM實例坦敌,并分配有唯一的用戶ID侣诵。
Android進程何時開始?
必要時會啟動Android進程狱窘。
每當用戶或其他系統(tǒng)組件請求執(zhí)行屬于您應(yīng)用程序的組件(可能是服務(wù)杜顺,活動或意圖接收器)時,Android系統(tǒng)都會為您的應(yīng)用程序啟動一個新進程(如果尚未運行)蘸炸。通常躬络,進程一直運行直到被系統(tǒng)殺死。應(yīng)用程序流程是按需創(chuàng)建的搭儒,在您看到應(yīng)用程序的啟動活動啟動并運行之前穷当,發(fā)生了許多事情。
每個應(yīng)用程序都在其自己的進程中運行:默認情況下淹禾,每個Android應(yīng)用程序都在其自己的Android進程中運行馁菜,而這個進程只不過是一個Linux進程,而該進程首先需要一個執(zhí)行線程铃岔。例如汪疮,當您單擊電子郵件中的超鏈接時,網(wǎng)頁將在瀏覽器窗口中打開德撬。您的郵件客戶端和瀏覽器是兩個單獨的應(yīng)用程序铲咨,它們分別在兩個單獨的進程中運行。click事件使Android平臺啟動新進程蜓洪,以便它可以在其自身進程的上下文中實例化瀏覽器活動纤勒。這對于應(yīng)用程序中的任何其他組件同樣適用。
Zygote:孕育新生命隆檀,新過程
讓我們退后一會兒摇天,快速瀏覽一下系統(tǒng)啟動過程粹湃。與大多數(shù)基于Linux的系統(tǒng)一樣,啟動加載程序在啟動時將加載內(nèi)核并啟動init進程泉坐。然后为鳄,init會生成稱為“守護程序”的低級Linux進程,例如android debug守護程序腕让,USB守護程序等孤钦。這些守護程序通常處理低級硬件接口,包括無線電接口纯丸。
然后偏形,初始化過程會啟動一個非常有趣的過程,稱為“zygote'觉鼻。
顧名思義俊扭,這是其余Android應(yīng)用程序的開始。這是初始化Dalvik虛擬機的第一個實例的過程坠陈。它還預(yù)加載Android應(yīng)用程序框架和系統(tǒng)上安裝的各種應(yīng)用程序使用的所有常見類萨惑。因此,它準備進行復(fù)制仇矾。它統(tǒng)計偵聽套接字接口上的將來請求庸蔼,以產(chǎn)生新的虛擬機(VM)來管理新的應(yīng)用程序進程。收到新請求后贮匕,它會分叉以創(chuàng)建一個新進程朱嘴,該進程將獲取預(yù)先初始化的VM實例。
zygote之后粗合,init啟動運行時過程萍嬉。
然后zygote分叉以啟動一個名為System server的托管良好的進程。系統(tǒng)服務(wù)器在其自己的上下文中啟動所有核心平臺服務(wù)隙疚,例如活動管理器服務(wù)和硬件服務(wù)壤追。
此時,完整的堆棧已準備就緒供屉,可以啟動第一個應(yīng)用程序流程-主頁應(yīng)用程序行冰,該應(yīng)用程序顯示主屏幕(也稱為啟動器應(yīng)用程序)。
當用戶單擊啟動器中的應(yīng)用程序圖標時…
click事件被轉(zhuǎn)換為startActivity(intent)伶丐,并通過Binder IPC路由到ActivityManagerService悼做。ActvityManagerService執(zhí)行多個步驟
- 第一步是收集有關(guān)Intent對象目標的信息。這是通過在PackageManager對象上使用resolveIntent()方法來完成的哗魂。默認情況下肛走,使用PackageManager.MATCH_DEFAULT_ONLY和PackageManager.GET_SHARED_LIBRARY_FILES標志。
- 目標信息將保存回意圖對象中录别,以避免重新執(zhí)行此步驟朽色。
- 下一個重要步驟是檢查用戶是否具有足夠的特權(quán)來調(diào)用意圖的目標組件邻吞。這是通過調(diào)用grantUriPermissionLocked()方法完成的。
- 如果用戶具有足夠的權(quán)限葫男,ActivityManagerService會檢查是否需要在新任務(wù)中啟動目標活動抱冷。任務(wù)的創(chuàng)建取決于Intent標志(例如FLAG_ACTIVITY_NEW_TASK)和其他標志(例如FLAG_ACTIVITY_CLEAR_TOP)。
- 現(xiàn)在梢褐,它的時間來檢查ProcessRecord已經(jīng)存在process.If的ProcessRecord為空旺遮,則ActivityManager有可能創(chuàng)造一個新的進程實例化目標的組成部分。
如您所見盈咳,當用戶單擊圖標并啟動新應(yīng)用程序時趣效,許多事情發(fā)生在幕后。這是全圖:
流程啟動分為三個不同的階段:
- 流程創(chuàng)建
- 裝訂申請
- 啟動活動/啟動服務(wù)/調(diào)用意圖接收器…
流程創(chuàng)建:
ActivityManagerService通過調(diào)用startProcessLocked()方法創(chuàng)建一個新進程猪贪,該方法通過套接字連接將參數(shù)發(fā)送到Zygote進程。Zygote派生自己并調(diào)用ZygoteInit.main()讯私,然后實例化ActivityThread對象并返回新創(chuàng)建的進程的進程ID热押。
默認情況下,每個進程都有一個線程斤寇。主線程有一個Looper實例來處理來自消息隊列的消息桶癣,并且它在run()方法的每次迭代中都調(diào)用Looper.loop()。Looper的工作是從消息隊列中彈出消息并調(diào)用相應(yīng)的方法來處理它們娘锁。然后牙寞,ActivityThread通過隨后調(diào)用Looper.prepareLoop()和Looper.loop()來啟動消息循環(huán)。
以下序列詳細捕獲了調(diào)用序列:
<figcaption class="jv jw di dg dh jx jy bo b fc cp ga" data-selectable-paragraph="" style="box-sizing: inherit; font-weight: 400; font-family: sohne, "Helvetica Neue", Helvetica, Arial, sans-serif; line-height: 20px; margin-left: auto; margin-right: auto; max-width: 728px; font-size: 14px; color: rgb(117, 117, 117); margin-top: 10px; text-align: center;">Android應(yīng)用啟動:單擊事件以執(zhí)行Looper調(diào)用順序</figcaption>
應(yīng)用程序綁定:
下一步是將此新創(chuàng)建的過程附加到特定應(yīng)用程序莫秆。這是通過在線程對象上調(diào)用bindApplication()來完成的间雀。此方法將BIND_APPLICATION消息發(fā)送到消息隊列。該消息由Handler對象檢索镊屎,該對象隨后調(diào)用handleMessage()方法以觸發(fā)特定于消息的操作-handleBindApplication()惹挟。此方法調(diào)用makeApplication()方法,該方法將應(yīng)用程序特定的類加載到內(nèi)存中缝驳。
下圖描述了該調(diào)用序列连锯。
<figcaption class="jv jw di dg dh jx jy bo b fc cp ga" data-selectable-paragraph="" style="box-sizing: inherit; font-weight: 400; font-family: sohne, "Helvetica Neue", Helvetica, Arial, sans-serif; line-height: 20px; margin-left: auto; margin-right: auto; max-width: 728px; font-size: 14px; color: rgb(117, 117, 117); margin-top: 10px; text-align: center;">Android應(yīng)用啟動:BIND_APPLICATION消息處理</figcaption>
啟動活動:
在上一步之后,系統(tǒng)包含負責應(yīng)用程序的進程用狱,并將應(yīng)用程序類加載到進程的私有內(nèi)存中运怖。在新創(chuàng)建的流程和現(xiàn)有流程之間,啟動活動的調(diào)用順序很常見夏伊。
實際的啟動過程從realStartActivity()方法開始摇展,該方法在應(yīng)用程序線程對象上調(diào)用sheduleLaunchActivity()。此方法將LAUNCH_ACTIVITY消息發(fā)送到消息隊列溺忧。該消息由handleLaunchActivity()方法處理吗购,如下所示医男。
假設(shè)用戶單擊“視頻瀏覽器”應(yīng)用程序。啟動該活動的調(diào)用順序如圖所示捻勉。
<figcaption class="jv jw di dg dh jx jy bo b fc cp ga" data-selectable-paragraph="" style="box-sizing: inherit; font-weight: 400; font-family: sohne, "Helvetica Neue", Helvetica, Arial, sans-serif; line-height: 20px; margin-left: auto; margin-right: auto; max-width: 728px; font-size: 14px; color: rgb(117, 117, 117); margin-top: 10px; text-align: center;">Android應(yīng)用啟動:LAUNCH_ACTIVITY消息處理</figcaption>
該活動通過onCreate()方法調(diào)用開始其托管生命周期镀梭。該活動通過onRestart()調(diào)用進入前臺,并通過onStart()調(diào)用開始與用戶進行交互踱启。