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