恋恋波尔多 www.luaogj.com.cn APP優化是我們進階高級開發工程師的必經之路,而APP啟動速度的優化,也是我們開啟APP優化的第一步。
用戶在使用我們的軟件時,交互最多最頻繁的也就是APP的啟動頁面,如果啟動頁面加載過慢,很可能造成用戶對我們APP的印象過差,進而消耗了用戶的耐心,更嚴重可能導致用戶的卸載行為。這也是微信始終堅持使用“一個小人望著地球”作為啟動頁面的背景,并且堅持不添加啟動廣告的的原因。
來看一下Google官方文檔《Launch-Time Performance》對應用啟動優化的概述;
應用的啟動可以分為冷啟動,熱啟動和溫啟動,而啟動最慢、耗時最長的就是冷啟動。
當應用啟動時,后臺沒有該應用的進程(常見如:進程被殺、首次啟動等),這時系統會重新創建一個新的進程分配給該應用。
這種啟動會從已有的進程中來啟動應用,通俗來講就是已經啟用的應用,通過back鍵或者home鍵回到系統主界面,再次通過最近任務重新打開Activity的過程??壤淦舳?。
暖啟動產生的場景很多。常見如:1。用戶使用返回鍵退出應用,然后馬上又重新啟動應用。2.應用被內存清除,再次打開應用,會通過OnCreate()中保存的實例狀態恢復。
冷啟動是從頭開始啟動APP,而其他兩種啟動方式是從后臺活動返回到前臺的一個過程。熱啟動和暖啟動沒有明顯的區分界限,我們姑且把熱啟動和暖啟動統稱為熱啟動??⒅形頤歉嗟墓刈⒗淦舳嘔?,本文也是從Android的實例從發,分析冷啟動的啟動過程,并給出冷啟動的優化方案。
冷啟動開始時,系統會依次執行三個任務去啟動APP:
加載和啟動應用程序
APP啟動后,立即創建一個空白的啟動Window
創建APP的進程
在這三個任務執行后,系統創建了應用進程,那么應用進程接下來會執行下一步:
創建APP對象
開啟一個主線程
創建啟動頁的Activity
加載View
布局view到屏幕
進行初始繪制顯示視圖
當應用進程完成初始繪制之后,系統進程用啟動頁的Activity來替換當前顯示的空白Window,這個時刻用戶就可以使用App了。
APP的啟動時間是我們可以檢驗優化效果的依據,啟動時間是指打開應用從初始化到顯示啟動頁Activity的這一段時間。
Google官方的解釋:APP startup time
在Android4.4(API level 19)以上的Android版本上,當啟動應用時Android Studio自動會在logcat中輸出啟動時間。 這個時間從應用啟動(創建進程)開始計算,到完成視圖的第一次繪制(即Activity內容對用戶可見)為止。
如Display顯示:
I/ActivityManager: Displayed com.example.app/com.example.app.SplashActivity: +1s742ms (total +49s450ms)
Activity 的reportFullyDrawn()方法,它會在Logcat里打印從apk初始化到reportFullyDrawn()方法被調用用了多長時間(文章的reportFullyDrawn()在SplashActivity中的onCreate()中執行,可以看到顯示的時間和Displayed的是一摸一樣的)
I/ActivityManager: Fully drawn com.example.app/com.example.app.SplashActivity: +1s742ms (total +49s450ms)
執行adb命令手動查看啟動時間
adb shell am start -W [packagename]/[packagename.SplashActivity]
Starting: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] cmp=com.example.app/.SplashActivity }
Status: ok
Activity: com.example.app/.SplashActivity
ThisTime: 1368
TotalTime: 1368
WaitTime: 1432
Complete
ThisTime:最后一個啟動的Activity的啟動耗時;
TotalTime:自己的所有Activity的啟動耗時;
只用關注TotalTime就行了
官方給出,當啟動時間超出以下指標時,會被認為啟動時間過長,這是就需要考慮仔細優化啟動時間。
冷啟動時間超過5s
熱啟動時間超過1.5s
暖啟動時間超過2s
說了一大堆啟動的基礎知識,下邊開始講解真正的優化實戰
解決應用剛啟動時的白屏問題
前邊講到,應用初始化會進行一系列進程的創建,資源的初始化工作,這段時間系統會先分配一個空白的Window,這會造成用戶打開應用到顯示第一個可交互的Activity,會經歷一段白屏的時間。
這時我們可以在給app定義一個主題去解決,在Activity顯示出來之前先顯示一個主題背景,去填補空白的Window階段。
<!--Splash launcher-->
<style name="LauncherTheme" parent="AppTheme">
<item name="android:windowBackground">@mipmap/ic_splash_bg</item>
<item name="android:windowFullscreen">true</item>
<item name="android:windowContentOverlay">@null</item>
</style>
<activity android:name=".activity.SplashActivity"
android:theme="@style/Launcher">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setTheme(R.style.AppTheme)
setContentView(R.layout.activity_splash)
}
這種方法只是視覺上給用戶一種快速啟動的感覺,不能減少實際的啟動時間。
隨著我們工程越做越大,第三方庫和組件也逐漸被依賴到我們的項目中,避免不了會在Application的onCreate()中執行很多第三方庫的初始化工作。大量的初始化工作導致該生命周期過于沉重,可能會加長應用的啟動時間,因此我們應該對這些第三方庫進行分類和優化。
必須在onCreate()且是主進程中初始化
可以延遲,但是需要在Application中初始化
可以延遲到啟動頁的生命周期回調中初始化
延遲到用的時候再初始化
大家可以根據自身項目去整理代碼,可以延遲執行的應該放在IntentService或者Work Thread中進行初始化。
例如EventBus 需要在Activiy中使用的,必須在Application中初始化
例如Bugly ,GrowingIO等類似庫的可以放在Work Thread中初始化
例如地圖定位、ImageLoad可以延遲到使用之前初始化
SplashActivity中網絡加載的資源,可以首次加載存放在緩存中,下次啟動的時候再顯示
注意有些第三方庫必須在主線程中初始化
避免耗時操作,如數據庫I/O操作不要放在主線程執行
刪除無用或重復的代碼
減少首屏Activity中的網絡請求密度