Jetpack之Startup快速掌握

冬天的毛毛雨發表於2020-12-23

好文推薦
作者:LKV_劉言

功能

用於為App提供初始化回撥能力。體系化得將各種App內的功能模組、所引入的SDK的初始化聯合起來,不各自為戰。一方面能夠將所有的初始化方式進行統一,在程式碼學習層面便於進入。另一方面,在初始化方式收斂後也能夠有效的做效能資料監控。

配置

implementation "androidx.startup:startup-runtime:1.0.0"

使用

實現子類

每一個需要初始化的元件實現一個Initializer<T>的子類

並實現兩個方法:

  • create這個方法要求返回你要初始化的元件的物件例項,可以new出來,也可以使用Builder等等,by your self
  • dependencies這個方法用來返回一系列的Initializer的子類的Class集合。意義是告知初始化框架,當前這個元件的初始化需要依賴其他的哪些元件初始化。可以沒有有效內容。

例項(來自官方)

// Initializes WorkManager.
class WorkManagerInitializer : Initializer<WorkManager> {
    override fun create(context: Context): WorkManager {
        val configuration = Configuration.Builder().build()
        WorkManager.initialize(context, configuration)
        return WorkManager.getInstance(context)
    }
    override fun dependencies(): List<Class<out Initializer<*>>> {
        // No dependencies on other libraries.
        return emptyList()
    }
}

宣告Manifest

兩點注意:

  • 要在Manifest中宣告其原理中真正使用的ContentProvider類androidx.startup.InitializationProvider,注意author要攜帶${applicationId}來避免與其他App產生衝突
  • 記得一定要在這個provider下宣告meta-data

第一點不做解釋了,其基本原理就是依靠ContentProvider的onCreate會在應用初始化時被自動呼叫這一點。

關於第二個需要解釋:

Startup會去找自己Provider下宣告的第一個meta-data所對應的類,來對他進行初始化,如果他宣告瞭他有依賴項,那麼他的依賴項也會被初始化。這樣,一個初始化鏈路就行程了。

例項:

<provider
    android:name="androidx.startup.InitializationProvider"
    android:authorities="${applicationId}.androidx-startup"
    android:exported="false"
    tools:node="merge">
    <!-- This entry makes ExampleLoggerInitializer discoverable. -->
    <meta-data  android:name="com.example.ExampleLoggerInitializer"
          android:value="androidx.startup" />
</provider>

meta-data支援宣告多個,只要他們的android:value都是androidx.startup就會被收集到:

原理

概覽

核心

ContentProvider的onCreate生命週期會在Application的onCreate之前被ActivityThread呼叫:

並且,這個行為是系統行為,不需要使用者去主動觸發,也就節省了XXX.init這種程式碼呼叫。

流程

  • InitializationProvider呼叫AppInitializer.discoverAndInitialize()方法
  • AppInitializer.discoverAndInitialize()掃描AndroidManifest.xml中InitializationProvider下的註冊資訊中的meta-data進行初始化元件發現:

需要注意的是:

  1. 只要meta-dataandroid:valueandroidx.startup那麼就可以被收集到,後續的觸發是按照在Manifest中宣告的順序進行的
  2. 截圖中程式碼沒有提到的,會使用Map mInitialized來確保每個類只會被初始化一次,而通過臨時的initializing確保在依賴關係中不允許迴圈依賴

第二點可以在下一步得到驗證:

  • 呼叫AppInitializer.doInitialize()

補充該方法的後續程式碼:

總結

  1. 初始化類應該具有public的無參建構函式
  2. 初始化中的狀態通過Set儲存Class達成,初始化完成的狀態由Map以Class為Key,對應create所產生的物件為Value表達
  3. 不能有迴圈依賴

寫在最後

Startup庫無疑為開發者提供了最為便捷的初始化方式,並且還貼心的提供了初始化項按照依賴關係進行的功能。但筆者認為,其在成熟、多樣的產品中,有幾點不足:

  1. 不支援外部定製、監聽相關初始化資料,如初始化時間的上報和超時報警
  2. 不支援延遲初始化、懶載入初始化等多樣的初始化型別
  3. 與2類似,其初始化型別單一,或者說都可以認為是普通的初始化。如果想要在所有前邊插入一個、所有後邊插入一個作為特殊的初始化項,那麼還需要開發者自行開發

一來,通過本文讀者可以更明白該元件背後做了什麼,可以更加自信、篤定、靈活的使用。另一方面,如果也認可筆者提到的問題的話,相信解法也是相對比較明確的,相信大家可以打造出適合自己的工具。

大家如果還想了解更多Android 相關的更多知識點,可以加入Android粉絲交流群872206502


粉絲交流群
在這裡插入圖片描述

相關文章