各位戰士,早安!昨天我們已經學會了如何精確測量敵人的實力(啟動耗時)。今天,我們將發起第一次外科手術式的打擊,目標是冷啟動過程中最關鍵的瓶頸——Application.onCreate()
方法。
為什麼是它?因為在冷啟動時,Application.onCreate()
是系統建立你的應用程式進程後,第一個執行的你自己的程式碼。它在主執行緒 (UI Thread) 上運行,並且會完全阻塞後續 Activity
的建立和渲染。簡單來說,它每多執行 1 毫秒,你的使用者就得多盯著白屏 1 毫秒。
Application
是否過於臃腫?許多開發者習慣將各種第三方函式庫的初始化、全域物件的設定等工作全部塞進 Application.onCreate()
。這是一個非常危險的習慣。檢查一下你的程式碼,是否存在以下「壞味道」:
Application
中建立完整的依賴圖可能非常耗時。SharedPreferences
、預載入資料庫、解壓縮資源檔等。我們的目標是:讓 Application.onCreate()
變得極度輕量,只做最最必要的事情。
為了解決這個問題,Google 在 Jetpack 中為我們提供了一把鋒利的手術刀——App Startup 函式庫。
App Startup 提供了一種高效、解耦的方式來管理應用程式啟動時的元件初始化。它的核心思想是:
Initializer
中,而不是全部堆在 Application
裡。Application.onCreate()
class MyApplication : Application() {
override fun onCreate() {
super.onCreate()
// 1. 初始化日誌工具
Timber.plant(Timber.DebugTree())
// 2. 初始化分析工具 (假設它依賴日誌工具)
AnalyticsSDK.initialize(this)
// 3. 初始化一個耗時的資料庫 (假設它不依賴任何人)
HeavyDatabase.getInstance(this)
}
}
這個寫法有幾個問題:所有東西都在主執行緒上同步執行,而且初始化邏輯緊密耦合在 Application
類別中。
步驟 1:加入依賴
在 app/build.gradle.kts
中加入 App Startup 的依賴:
implementation("androidx.startup:startup-runtime:1.1.1")
步驟 2:為每個元件建立 Initializer
// 1. 建立日誌工具的 Initializer
class TimberInitializer : Initializer<Unit> {
override fun create(context: Context) {
Timber.plant(Timber.DebugTree())
}
// 沒有依賴其他元件
override fun dependencies(): List<Class<out Initializer<*>>> = emptyList()
}
// 2. 建立分析工具的 Initializer
class AnalyticsInitializer : Initializer<AnalyticsSDK> {
override fun create(context: Context): AnalyticsSDK {
// 假設 AnalyticsSDK 初始化後會返回一個實例
return AnalyticsSDK.initialize(context)
}
// 明確聲明它依賴 TimberInitializer
override fun dependencies(): List<Class<out Initializer<*>>> = listOf(TimberInitializer::class.java)
}
// 3. 建立資料庫的 Initializer
class DatabaseInitializer : Initializer<HeavyDatabase> {
override fun create(context: Context): HeavyDatabase {
return HeavyDatabase.getInstance(context)
}
// 沒有依賴
override fun dependencies(): List<Class<out Initializer<*>>> = emptyList()
}
步驟 3:在 AndroidManifest.xml
中註冊
這是最關鍵的一步。我們透過 provider
標籤來註冊這些 Initializer
,並完全移除 MyApplication 中的初始化程式碼。
<provider
android:name="androidx.startup.InitializationProvider"
android:authorities="${applicationId}.androidx-startup"
android:exported="false"
tools:node="merge">
<!-- 註冊 TimberInitializer -->
<meta-data android:name="com.example.TimberInitializer"
android:value="androidx.startup" />
<!-- 註冊 AnalyticsInitializer -->
<meta-data android:name="com.example.AnalyticsInitializer"
android:value="androidx.startup" />
<!-- 註冊 DatabaseInitializer -->
<!-- 如果某個元件不是啟動時必須的,可以將其設定為懶加載 -->
<!-- 這裡我們假設資料庫不是,所以移除它的 meta-data 來實現懶加載 -->
<!--
<meta-data android:name="com.example.DatabaseInitializer"
android:value="androidx.startup" />
-->
</provider>
完成後,你的 Application.onCreate()
就可以變得乾乾淨淨!App Startup 會自動按照你定義的依賴順序,在 ContentProvider
的 onCreate
階段完成所有初始化工作。
今日總結
今天,我們對 Application.onCreate()
進行了一次成功的瘦身手術。
我們認識到 Application.onCreate() 是冷啟動的關鍵瓶頸。
我們學會了使用 App Startup 函式庫來解耦和管理初始化任務。
我們掌握了透過定義 Initializer
和在 AndroidManifest
中註冊,來實現自動化、有序的初始化流程。
透過這場手術,我們不僅讓 Application
類別的程式碼變得更清晰,更重要的是,我們為後續更細緻的優化(例如將某些任務移出主執行緒)打下了堅實的基礎。
Application
階段的戰役暫告一段落。明天,我們將把戰線推進到 Activity
層級,探討如何優化第一幀的繪製,讓使用者能更快地看到有意義的畫面。
我們明天見!