安卓使用 Startup 管理三方 SDK 初始化
一、为什么要使用 Startup?
1. 第三方 SDK 是怎么 "悄悄初始化" 的?
很多 popular SDK(如 Bugly、友盟、高德地图、MMKV、各类推送与统计 SDK)都在自己的 AAR 包里内置了一个 ContentProvider。
它会在 AndroidManifest.xml 中注册类似这样的配置:
xml
<provider
android:name="com.xxx.XXXProvider"
android:authorities="${applicationId}.xxx"
android:exported="false" />
而在这个 Provider 的 onCreate() 里,它会偷偷执行 SDK 初始化:
java
@Override
public void onCreate() {
XXXSDK.init(getContext()); // 自动初始化
}
你什么都不用做,App 一启动,几十个 SDK 就在主线程排队初始化,直接拖慢冷启动速度。
2. 为什么 ContentProvider 会自动执行?
系统启动 App 的流程是固定的:
- Zygote 孵化出 App 进程
- 创建 Application,执行
attachBaseContext() - 实例化并执行所有 Manifest 中注册的 ContentProvider
- 执行
Application.onCreate() - 启动第一个 Activity
关键点:
ContentProvider 的 onCreate () 会在 Application.onCreate () 之前自动执行!
所以 SDK 利用这个 "系统钩子" 实现自动初始化,结果就是:
App 还没进入你的代码,已经被一堆 SDK 卡死在启动阶段。
3. Jetpack Startup 解决了什么问题?
App Startup 的核心使命非常简单:
用一个统一的 ContentProvider,替代所有 SDK 各自为政的 N 个 ContentProvider。
只保留一个:
xml
<provider
android:name="androidx.startup.InitializationProvider"
android:authorities="${applicationId}.androidx-startup"
android:exported="false" />
好处:
- 减少大量组件创建开销
- 统一管理 SDK 初始化顺序
- 支持依赖声明 → 自动拓扑排序
- 支持手动 / 懒加载控制
它不是禁用 ContentProvider,而是把被滥用的 "自动初始化钩子" 重新收归统一管理。
4.Startup 的核心作用总结
- 取消每个 SDK 自己私有的 Provider
- 把所有初始化逻辑集中到你写的 Initializer
- 通过 dependencies () 声明依赖 → 自动按顺序执行
- 不会乱并发、不会乱序、不会阻塞主线程
二、使用startup
1. 引入依赖
groovy
implementation "androidx.startup:startup-runtime:1.2.0"
2. 新建多个Initializer类
MainInitializer.kt
备注:统一入口,可选
kotlin
package com.example.startupdemo.initializer
import android.content.Context
import androidx.startup.AppInitializer
import androidx.startup.Initializer
class MainInitializer : Initializer<Unit> {
override fun create(context: Context) {
// ========== 这里写所有需要启动初始化的库 ==========
println("初始化:MainInitializer")
initNetwork(context)
initPush(context)
// initBugly(context)
// initMMKV(context)
// initRouter(context)
}
// 网络
private fun initNetwork(context: Context) {
AppInitializer.getInstance(context)
.initializeComponent(NetworkInitializer::class.java)
}
// 推送
private fun initPush(context: Context) {
AppInitializer.getInstance(context)
.initializeComponent(PushInitializer::class.java)
}
// 依赖:如果没有依赖其他Initializer,就空
override fun dependencies(): List<Class<out Initializer<*>>> = emptyList()
}
CrashInitializer.kt
kotlin
package com.example.startupdemo.initializer
import android.content.Context
import androidx.startup.Initializer
class CrashInitializer : Initializer<Unit> {
override fun create(context: Context) {
// 执行崩溃库初始化
println("初始化:崩溃监控")
}
/**
* 表示当前的 Initializer 是否还依赖于其他的 Initializer,如果有的话就在这里进行配置,
* App Startup 会保证先初始化依赖的 Initializer,然后才会初始化当前的 Initializer
*/
override fun dependencies(): List<Class<out Initializer<*>>> = emptyList()
}
NetworkInitializer.kt
kotlin
package com.example.startupdemo.initializer
import android.content.Context
import androidx.startup.Initializer
class NetworkInitializer : Initializer<Unit> {
override fun create(context: Context) {
// 执行网络库初始化
println("初始化:网络框架")
}
/**
* 表示当前的 Initializer 是否还依赖于其他的 Initializer,如果有的话就在这里进行配置,
* App Startup 会保证先初始化依赖的 Initializer,然后才会初始化当前的 Initializer
*/
override fun dependencies(): List<Class<out Initializer<*>>> = listOf(CrashInitializer::class.java)
}
PushInitializer.kt
kotlin
package com.example.startupdemo.initializer
import android.content.Context
import androidx.startup.Initializer
class PushInitializer : Initializer<Unit> {
override fun create(context: Context) {
// 执行推送初始化
println("初始化:推送服务")
}
/**
* 表示当前的 Initializer 是否还依赖于其他的 Initializer,如果有的话就在这里进行配置,
* App Startup 会保证先初始化依赖的 Initializer,然后才会初始化当前的 Initializer
*/
override fun dependencies(): List<Class<out Initializer<*>>> = listOf(NetworkInitializer::class.java)
}
3. 初始化
方式 A:代码手动初始化(推荐)
更灵活、不抢启动、最安全:
kotlin
// 在 Application 或 MainActivity 中
AppInitializer.getInstance(this)
.initializeComponent(MainInitializer::class.java)
方式 B:XML 自动初始化(不推荐)
xml
<provider
android:name="androidx.startup.InitializationProvider"
android:authorities="${applicationId}.androidx-startup"
android:exported="false"
tools:node="merge">
<meta-data
android:name="com.example.startupdemo.initializer.MainInitializer"
android:value="androidx.startup" />
</provider>
警告:如果不用 XML 配置,可以删除
<meta-data>,或使用tools:node="remove"让它失效。
4. 运行结果与demo
初始化:MainInitializer
初始化:崩溃监控
初始化:网络框架
初始化:推送服务
为什么顺序是这样?
- NetworkInitializer 依赖 CrashInitializer
- PushInitializer 依赖 NetworkInitializer
- Startup 自动执行 拓扑排序 → 先依赖,后当前
由此实现:
- 初始化顺序完全可控
- 自动初始化 vs 懒加载 二选一
- 启动速度显著提升(减少 ContentProvider 数量)
- 代码结构更清晰、更好维护