前幾天 Google 更新了幾個 Jetpack 新成員 Hilt、Paging 三、App Startup 等等,週末空閒時間實踐了一下 App Startup 能夠前去查看 GitHub 上的項目 AndroidX-Jetpack-Practice ,接下來一塊兒來分析一下 AndroidX App Startup。java
經過這篇文章你將學習到如下內容:node
來自 Google 文檔: App Startup 是 Android Jetpack 最新成員,提供了在 App 啓動時初始化組件簡單、高效的方法,不管是 library 開發人員仍是 App 開發人員均可以使用 App Startup 顯示的設置初始化順序。android
簡單的說就是 App Startup 提供了一個 ContentProvider 來運行全部依賴項的初始化,避免每一個第三方庫單獨使用 ContentProvider 進行初始化,從而提升了應用的程序的啓動速度。git
不管是 Google 提供的庫仍是第三方庫,啓動時運行一些初始化邏輯並很多見,例如 WorkManager 在應用啓動時使用 ContentProvider 進行初始化,來看一下 Google 工程師 Husayn Hakeem 分享的一張的圖。github
上圖表示如今咱們有三個庫分別 LibraryA、LibraryB、和 LibraryC 它們使用本身的 ContentProviders 進行初始化。面試
而 App Startup 提供了一個 ContentProvider 來運行全部依賴項的初始化(LibraryA、LibraryB、和 LibraryC),以下圖所示。算法
剛纔咱們說到不管是 Google 提供的庫仍是第三方庫,App 啓動運行時會初始化一些邏輯,它們爲了方便開發者使用,避免開發者手動調用,使用 ContentProvider 進行初始化,例如 WorkManager 在應用啓動時使用 ContentProvider 進行初始化,咱們來看一下 WorkManager 的源碼,先來看一下 AndroidManifest.xml 文件內容。編程
如上所見,咱們能夠看到在 AndroidManifest.xml 文件內定義了一個名爲 WorkManagerInitializer 的 ContentProvider,我來看看 WorkManagerInitializer 裏面都作了什麼。數組
public class WorkManagerInitializer extends ContentProvider {
@Override
public boolean onCreate() {
// Initialize WorkManager with the default configuration.
WorkManager.initialize(getContext(), new Configuration.Builder().build());
return true;
}
......
// 省略了沒用的代碼
}
複製代碼
如上所見其實就是在 WorkManagerInitializer 的 onCreate() 方法裏面,使用默認配置初始化 WorkManager。性能優化
咱們也來模仿 WorkManager 寫一個 Demo,這裏只貼出部分代碼,更多信息查看 GitHub 上的 AppStartupSimple 下面的 ContentProvider 模塊。
class WorkContentProvider : ContentProvider() {
override fun onCreate(): Boolean {
Log.d(TAG, "WorkContentProvider create()")
return true
}
.....
}
複製代碼
<application>
<provider
android:name=".WorkContentProvider"
android:authorities="${applicationId}.provider"
android:exported="false" />
</application>
複製代碼
com.hi.dhl.startup.simple D/WorkContentProvider: WorkContentProvider create()
複製代碼
假設你的 App 有不少相似於 WorkManager 這樣的庫,都在 ContentProvider 裏面進行一些初始化工做,在 App 啓動時運行多個 ContentProvider,這樣會帶來一些問題:
private void handleBindApplication(AppBindData data) {
......
if (!data.restrictedBackupMode) {
if (!ArrayUtils.isEmpty(data.providers)) {
// 建立ContentProvider
installContentProviders(app, data.providers);
}
}
......
try {
// 調用調用 Application 的 OnCreate 方法
mInstrumentation.callApplicationOnCreate(app);
} catch (Exception e) {
......
}
......
}
複製代碼
這是在 App 冷啓動時自動運行初始化的,這樣只會增長 App 的加載時間,用戶但願 App 加載得快,啓動慢會帶來糟糕的用戶體驗,AndroidX App Startup 正是爲了解決這個問題而出現的。
使用 AndroidX App Startup 來運行全部依賴項的初始化有兩種方式:
具體能夠查看 GitHub 上的 AppStartupSimple 下面的 Startup-Library 模塊相關代碼。
implementation "androidx.startup:startup-runtime:1.0.0-alpha01"
複製代碼
class LibaryC : Initializer<LibaryC.Dependency> {
override fun create(context: Context): Dependency {
// 初始化工做
Log.e(TAG, "init LibaryC ")
return Dependency()
}
override fun dependencies(): MutableList<Class<out Initializer<*>>> {
return mutableListOf(LibaryB::class.java)
}
......
}
複製代碼
正如 GitHub 上的 AppStartupSimple 示例項目,它依賴結構就是 LibaryC 依賴於 LibaryB,LibaryB 依賴於 LibaryA,輸出結果以下所示:
com.hi.dhl.startup.simple E/LibaryA: init LibaryA
com.hi.dhl.startup.simple E/LibaryB: init LibaryB
com.hi.dhl.startup.simple E/LibaryC: init LibaryC
複製代碼
<application>
<provider
android:name="androidx.startup.InitializationProvider"
android:authorities="${applicationId}.androidx-startup"
android:exported="false"
tools:node="merge">
<!-- 自動初始化 -->
<meta-data
android:name="com.hi.dhl.startup.library.LibaryC"
android:value="androidx.startup" />
</provider>
</application>
複製代碼
App 啓動的時 App Startup 會讀取 AndroidManifest.xml 文件裏面的 InitializationProvider 下面的 <meta-data>
聲明要初始化的組件,完成自動初始化工做。
<application>
<provider
android:name="androidx.startup.InitializationProvider"
android:authorities="${applicationId}.androidx-startup"
android:exported="false"
tools:node="merge">
<!-- 手動初始化(也是延遲初始化) -->
<meta-data
android:name="com.hi.dhl.startup.library.LibaryD"
android:value="androidx.startup"
tools:node="remove" />
</provider>
</application>
複製代碼
只須要在 <meta-data>
標籤內添加 tools:node="remove"
清單合併工具會將它從清單文件中刪除。
AppInitializer.getInstance(context).initializeComponent(MyInitializer::class.java)
複製代碼
若是組件初始化以後,再次調用 AppInitializer.initializeComponent() 方法不會再次初始化。
手動初始化(也是延遲初始化)是很是有用的,組件不須要在 App 啓動時運行,只須要在須要它地方運行,能夠減小 App 的啓動時間,提升啓動速度。
這篇文章主要介紹瞭如下內容:
<meta-data>
聲明要初始化的組件。計劃創建一個最全、最新的 AndroidX Jetpack 相關組件的實戰項目 以及 相關組件原理分析文章,正在逐漸增長 Jetpack 新成員,倉庫持續更新,能夠前去查看:AndroidX-Jetpack-Practice, 若是這個倉庫對你有幫助,請幫我點個贊,我會陸續完成更多 Jetpack 新成員的項目實踐。
致力於分享一系列 Android 系統源碼、逆向分析、算法、翻譯、Jetpack 源碼相關的文章,能夠關注我,若是你喜歡這篇文章歡迎 star,一塊兒來學習,期待與你一塊兒成長。
因爲 LeetCode 的題庫龐大,每一個分類都能篩選出數百道題,因爲每一個人的精力有限,不可能刷完全部題目,所以我按照經典類型題目去分類、和題目的難易程度去排序。
每道題目都會用 Java 和 kotlin 去實現,而且每道題目都有解題思路,若是你同我同樣喜歡算法、LeetCode,能夠關注我 GitHub 上的 LeetCode 題解:Leetcode-Solutions-with-Java-And-Kotlin,一塊兒來學習,期待與你一塊兒成長。
正在寫一系列的 Android 10 源碼分析的文章,瞭解系統源碼,不只有助於分析問題,在面試過程當中,對咱們也是很是有幫助的,若是你同我同樣喜歡研究 Android 源碼,能夠關注我 GitHub 上的 Android10-Source-Analysis,文章都會同步到這個倉庫。
目前正在整理和翻譯一系列精選國外的技術文章,不只僅是翻譯,不少優秀的英文技術文章提供了很好思路和方法,每篇文章都會有譯者思考部分,對原文的更加深刻的解讀,能夠關注我 GitHub 上的 Technical-Article-Translation,文章都會同步到這個倉庫。