一、app的啟動(dòng)流程包括的步驟
1、創(chuàng)建進(jìn)程
App發(fā)起進(jìn)程:當(dāng)從桌面啟動(dòng)應(yīng)用,則發(fā)起進(jìn)程便是Launcher所在進(jìn)程;當(dāng)從某App內(nèi)啟動(dòng)遠(yuǎn)程進(jìn)程,則發(fā)送進(jìn)程便是該App所在進(jìn)程。發(fā)起進(jìn)程先通過binder發(fā)送消息給system_server進(jìn)程。system_server進(jìn)程:調(diào)用Process.start()方法,通過socket向zygote進(jìn)程發(fā)送創(chuàng)建新進(jìn)程的請(qǐng)求。zygote進(jìn)程:在執(zhí)行ZygoteInit.main()后便進(jìn)入runSelectLoop()循環(huán)體內(nèi),當(dāng)有客戶端連接時(shí)便會(huì)執(zhí)行ZygoteConnection.runOnce()方法,再經(jīng)過層層調(diào)用后fork出新的應(yīng)用進(jìn)程。新進(jìn)程:執(zhí)行handleChildProc方法,最后調(diào)用ActivityThread.main()方法。2、綁定Application
上面創(chuàng)建進(jìn)程后,執(zhí)行ActivityThread.main()方法,隨后調(diào)用attach()方法。將進(jìn)程和指定的Application綁定起來。這個(gè)是通過ActivityThread對(duì)象中調(diào)用bindApplication()方法完成的,該方法發(fā)送一個(gè)BIND_APPLICATION的消息到消息隊(duì)列中,最終通過handleBindApplication()方法處理該消息,然后調(diào)用makeApplication()方法來加載App的classes到內(nèi)存中。
二、App啟動(dòng)方式
1、冷啟動(dòng)
當(dāng)啟動(dòng)應(yīng)用時(shí),后臺(tái)沒有該應(yīng)用的進(jìn)程,這時(shí)系統(tǒng)會(huì)重新創(chuàng)建一個(gè)新的進(jìn)程分配給該應(yīng)用,這個(gè)啟動(dòng)方式就是冷啟動(dòng)。冷啟動(dòng)因?yàn)橄到y(tǒng)會(huì)重新創(chuàng)建一個(gè)新的進(jìn)程分配給它,所以會(huì)先創(chuàng)建和初始化Application類,再創(chuàng)建和初始化MainActivity類(包括一系列的測量、布局、繪制),最后顯示在界面上。
2、熱啟動(dòng)
當(dāng)啟動(dòng)應(yīng)用時(shí),后臺(tái)已有該應(yīng)用的進(jìn)程(例:按back鍵、home鍵,應(yīng)用雖然會(huì)退出,但是該應(yīng)用的進(jìn)程是依然會(huì)保留在后臺(tái),可進(jìn)入任務(wù)列表查看),所以在已有進(jìn)程的情況下,這種啟動(dòng)會(huì)從已有的進(jìn)程中來啟動(dòng)應(yīng)用,這個(gè)方式叫熱啟動(dòng)。熱啟動(dòng)因?yàn)闀?huì)從已有的進(jìn)程中來啟動(dòng),所以熱啟動(dòng)就不會(huì)走Application這步了,而是直接走M(jìn)ainActivity(包括一系列的測量、布局、繪制),所以熱啟動(dòng)的過程只需要?jiǎng)?chuàng)建和初始化一個(gè)MainActivity就行了,而不必創(chuàng)建和初始化Application,因?yàn)橐粋€(gè)應(yīng)用從新進(jìn)程的創(chuàng)建到進(jìn)程的銷毀,Application只會(huì)初始化一次。
三、影響APP啟動(dòng)性能的因素
1、密集型應(yīng)用初始化
如果您在代碼中替換了Application對(duì)象,且在Application對(duì)象進(jìn)行初始化的時(shí)候執(zhí)行了密集的工作或者復(fù)雜的邏輯,那么您的啟動(dòng)性能就會(huì)受到影響。如果您的應(yīng)用子類執(zhí)行尚不需要完成的初始化,則應(yīng)用可能會(huì)在啟動(dòng)過程中浪費(fèi)更多的時(shí)間,并且有些初始化可能是完全不必要的。
如果Application 里面的初始化操作不結(jié)束的話,其他任意的程序操作都是無法進(jìn)行的。因此,在 Application 初始化的地方做太多密集的工作或者復(fù)雜的邏輯是導(dǎo)致啟動(dòng)性能問題的元兇之一。
在做 Application的初始化工作時(shí),很多組件是需要我們區(qū)別對(duì)待的,有些組件適合做延遲加載,有些則適合放到其他的地方做初始化操作,在此我們需要特別留意包含 Disk IO的操作,因?yàn)榫W(wǎng)絡(luò)訪問等嚴(yán)重耗時(shí)的任務(wù),是會(huì)嚴(yán)重影響程序啟動(dòng)的。
2、密集型 Activity 初始化
我們在創(chuàng)建 Activity 時(shí)通常需要開展大量的高開銷工作,用來提升 Activity 的創(chuàng)建速度,因?yàn)樘嵘?Activity 的創(chuàng)建速度是優(yōu)化 APP 啟動(dòng)速度的首要目標(biāo)。從桌面點(diǎn)擊 APP 圖標(biāo)啟動(dòng)應(yīng)用開始,程序會(huì)顯示一個(gè)啟動(dòng)窗口等待 Activity 的創(chuàng)建加載完畢再進(jìn)行顯示。在 Activity 的創(chuàng)建加載過程中,應(yīng)用會(huì)執(zhí)行很多的操作,例如設(shè)置頁面的主題,初始化頁面的布局,加載圖片,獲取網(wǎng)絡(luò)數(shù)據(jù),讀寫 Preference 等等。
上述操作的任何一個(gè)環(huán)節(jié)出現(xiàn)性能問題都可能導(dǎo)致畫面不能及時(shí)顯示,從而影響應(yīng)用程序的啟動(dòng)速度。
延伸閱讀1:密集型應(yīng)用初始化導(dǎo)致app啟動(dòng)性能差的解決方法
優(yōu)化這些問題的解決方案是給應(yīng)用做延遲加載處理,可以在 Application 里面做延遲加載,也可以將一些初始化的操作延遲到組件真正被調(diào)用的時(shí)候再做加載。例如,不創(chuàng)建全局靜態(tài)對(duì)象,而是轉(zhuǎn)為單例模式,其中應(yīng)用僅在名列前茅次訪問對(duì)象時(shí)初始化它們。