# Android 應用啟動時間(冷、溫、熱) ###### tags: `Tag(Android 技術相關)` [TOC] ## 了解應用啟動內部機制 - 三種啟動狀態 ### 冷啟動:App 開啟 * 進入三個任務 (1). 加載並啟動應用。 (2). 在啟動後立即顯示應用的==空白啟動窗口==。 (3). 創建應用進程。 * 創建應用進程,應用進程就負責後續階段: 1. 創建應用對象。 (Application onCreate) 2. 啟動主線程。 (MainThread) 3. 創建主Activity。(MainThread (Activity init)) 4. 擴充視圖。 (MainThread (Activity onCreate)) 5. 佈局屏幕。 (MainThread (Activity onCreate)) 6. 執行初始繪製。(MainThread (Activity onCreate)) ![](https://i.imgur.com/Yy97alI.png) * **一旦應用進程完成第一次繪製,系統進程就會換掉當前顯示的後台窗口,替換為主Activity。此時,用戶可以開始使用應用。** `注意: 應用中使Application.onCreate()過載,系統將在應用對像上調用onCreate()方法。之後,應用生成主線程(也稱為介面線程),並用其執行創建主Activity的任務。` * **創建主Activity -> 擴充視圖、佈局屏幕、執行初始繪製 -> Activity的當前生命週期狀態** `注意:onCreate()方法對加載時間的影響最大,因為它執行工作的開銷最高:加載和膨脹視圖,以及初始化運行Activity所需的對象。` --- ### 熱啟動 : 背景回前台 所有Activity 仍駐留在內存,不必重複執行對像初始化 * 但如果一些內存為響應內存整理事件(如onTrimMemory())而被完全清除,則需要為了響應熱啟動事件而重新創建相應的對象。 * **熱啟動顯示的屏幕上行為和冷啟動場景相同:在應用完成Activity 呈現之前,系統進程將顯示空白屏幕。** --- ### 溫啟動 : 透過onCreate()已保存的實例state bundle 溫啟動包含了在冷啟動期間發生的部分操作 * 用戶在==退出應用後又重新啟動應用==。進程可能已繼續運行,但應用必須通過調用onCreate()從頭開始重新創建Activity。 * 系統將您的應用從內存中逐出,然後用戶又重新啟動它。==進程和Activity需要重啟==,但傳遞到onCreate()的已保存的==實例state bundle==對於完成此任務有一定助益。 --- ### 效能比 : 冷啟動 > 溫啟動 > 熱啟動 --- ## 如何剖析啟動性能 ### Android Vitals - Play管理中心診斷提醒(只有冷啟動、溫啟動數據) * 其啟動時間視為過長: * 冷啟動用了**5秒**或更長時間。 * 溫啟動用了**2秒**或更長時間。 * 熱啟動用了**1.5秒**或更長時間。 ### Android studio - logcat 中 Displayed時間 ![](https://i.imgur.com/A96FB99.png) 報告的日誌行類似於以下示例: ActivityManager: Displayed com.android.myexample/.StartupTiming: +3s534ms // total時間測量值僅在單個Activity的時間和總啟動時間之間存在差異時才會顯示。 ActivityManager: Displayed com.android.myexample/.StartupTiming: +3s534ms (total +1m22s643ms) ### ADB Shell Activity Manager命令運行應用來測量初步顯示所用時間 ``` adb [-d|-e|-s <serialNumber>] shell am start -S -W com.example.app/.MainActivity -c android.intent.category.LAUNCHER -a android.intent.action.MAIN ``` ``` Displayed指標和以前一樣出現在logcat 輸出中。您的終端窗口還應顯示以下內容: Starting: Intent Activity: com.example.app/.MainActivity ThisTime: 2044 TotalTime: 2044 WaitTime: 2054 Complete ``` --- ## 常見問題類型 ### 密集型應用初始化 & 密集型Activity初始化 - 問題診斷 & 方法 #### 診斷問題 可以使用方法跟踪記錄或內嵌跟踪記錄來嘗試診斷問題。 #### 方法跟踪記錄 運行CPU性能剖析器顯示,callApplicationOnCreate()方法最終調用您的com.example.customApplication.onCreate方法。如果該工具顯示這些方法需要很長時間才能完成執行,您應該進一步探索以查看正在進行哪些工作。 #### 內嵌跟踪記錄 使用內嵌跟踪記錄調查可能的問題根源,包括: 1. 應用的初始onCreate()函數。 2. 應用初始化的任何全局單例對象。 3. 在瓶頸期間可能發生的任何磁盤I/O、反序列化或緊密循環。 --- ### 密集型應用初始化 - 問題解決方案 初始化該對象過程中執行密集工作或複雜邏輯時,啟動性能可能會受影響。如果您的應用子類執行尚不需要完成的初始化 #### 問題解決方案 不管問題在於不必要的初始化還是磁盤I/O,**解決方案都會調用延遲初始化對象**:僅初始化立即需要的對象。例如:**不創建全局靜態對象,而是轉為單例模式**,其中應用僅在第一次訪問對象時初始化它們。此外,考慮使用**依賴注入框架**(如Dagger),它們會在首次注入時創建對象和依賴項。 --- ### 密集型Activity初始化 - 問題解決方案 * 創建Activity 通常需要進行大量的高開銷工作。通常有機會優化這項工作以實現性能改進。此類常見問題包括: 1. 擴充大型或複雜的佈局。 2. 阻止磁盤上的屏幕繪製或網絡I/O。 3. 加載和解碼位圖。 4. 柵格化VectorDrawable對象。 5. 初始化Activity 的其他子系統。 #### 問題解決方案 * 潛在瓶頸有很多,但兩種常見問題和補救措施如下所示: * 視圖層次結構越大,應用膨脹它所花的時間就越長。解決此問題的兩個步驟是: 1. 減少冗餘或嵌套佈局,視圖層次結構。 2. 啟動期間無需顯示的界面部分。 * 主線程上進行所有資源初始化也會降低啟動速度 1. 轉移所有資源初始化,以便應用可以在其他線程上延遲執行。 2. 允許應用加載並顯示您的視圖,稍後再更新依賴於位圖和其他資源的可視屬性 --- ### 帶主題背景的啟動屏幕 - 診斷問題 & 問題解決方案 希望為應用的加載體驗設置主題背景,從而使應用的啟動屏幕在主題背景上與應用的其餘部分保持一致,而不是與系統主題背景一致。這樣做可以隱藏緩慢的Activity 啟動。 #### 診斷問題 觀察用戶啟動應用時,應用的響應是否很慢:在這種情況下,屏幕看起來會像是卡住了,或停止了對輸入做出響應。 #### 問題解決方案 windowBackground主題背景屬性,為啟動Activity提供簡單的自定義可繪製對象。 * 空白啟動窗口,創建新的可繪製文件 1. 布局 XML 文件 2. manifest文件中引用它 * 要切回到正常主題背景,最簡單的方式是先調用setTheme(R.style.AppTheme),然後再調用super.onCreate()和setContentView(): ```clike= class MyMainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { // Make sure this is before calling super.onCreate setTheme(R.style.Theme_MyApp) super.onCreate(savedInstanceState) // ... } } ``` ## 參考文獻: ### https://developer.android.com/topic/performance/vitals/launch-time?hl=zh-cn#kotlin