Android Jetpack 系列(七)App Startup 启动优化
1. 简介
应用启动阶段的性能至关重要。许多第三方 SDK 或库都需要在应用启动时完成初始化,而常见做法通常有两种:
传统方式一: 在 Application 的 onCreate() 中初始化
这种方式虽然直观,但存在几个问题:
问题 1:所有初始化逻辑都堆在 onCreate() 中,难以维护;
问题 2:如果库开发者也需要自动初始化,就必须依赖宿主应用的改动;
问题 3:对库作者来说,无法保证宿主是否正确初始化。
传统方式二: 通过 ContentProvider 自动初始化
为了让库能“自动”初始化,许多 SDK(如 WorkManager、Room、Firebase 等)会在自己的 AndroidManifest.xml 中声明一个 ContentProvider。
系统会在 Application.onCreate() 之前自动创建所有 Provider,这样库便能在应用启动前完成初始化。
但这种方式也存在问题:
问题 1:冷启动开销大,每个库一个 Provider,系统会在启动时反射并创建多个对象,增加启动时间。
问题 2:初始化顺序不可控,Android 并不保证 Provider 的执行顺序,若库之间存在依赖关系,容易出现初始化错误。
为此,Jetpack 推出了 App Startup,专门用于解决以上问题。App Startup 的优势:
- 简单配置即可实现自动初始化;
- 所有初始化逻辑共用一个 Provider,仅加载一次入口,性能更佳;
- 通过 dependencies() 显式声明依赖关系,保证顺序;
- 对应用开发者与库开发者都极为友好:
- 应用开发者可借此简化 Application 逻辑;
- 库开发者可实现“自动初始化”,无需宿主修改。
2. 添加依赖
要在项目中使用 App Startup,需要在模块的 build.gradle.kts 或 build.gradle 文件中添加如下依赖项:
dependencies {implementation("androidx.startup:startup-runtime:1.2.0")
}
3. 实现初始化组件
3.1. 实现 Initializer 接口
App Startup 的核心思想很简单,每个需要初始化的组件都对应一个 Initializer 类。实现 Initializer<T> 接口后,App Startup 就能在启动时自动调用它的 create() 方法完成初始化。
interface Initializer<T> {fun create(context: Context): Tfun dependencies(): List<Class<out Initializer<*>>>
}
方法说明:
- create():定义该组件的初始化逻辑。
- dependencies():声明依赖的其它组件初始化器,控制执行顺序。
我们在前面文章《Android Jetpack 系列(六)WorkManager 任务调度》中的【4.9.1. 默认自动初始化】中便介绍过 WorkManager 库能自动初始化正是因为它实现了这个接口,其源码如下:
public final class WorkManagerInitializer implements Initializer<WorkManager> {private static final String TAG = Logger.tagWithPrefix("WrkMgrInitializer");@NonNull@Overridepublic WorkManager create(@NonNull Context context) {// Initialize WorkManager with the default configuration.Logger.get().debug(TAG, "Initializing WorkManager with default configuration.");WorkManager.initialize(context, new Configuration.Builder().build());return WorkManager.getInstance(context);}@NonNull@Overridepublic List<Class<? extends androidx.startup.Initializer<?>>> dependencies() {return Collections.emptyList();}
}
3.2. 在 Manifest 中配置初始化器
App Startup 实际上是通过一个特殊的 ContentProvider 来发现并执行这些初始化器。该 Provider 名为:
androidx.startup.InitializationProvider
要启用自动初始化,只需在 AndroidManifest.xml 中添加 <meta-data> 配置。例如 WorkManager 的配置如下:
<application><providerandroid:name="androidx.startup.InitializationProvider"android:authorities="${applicationId}.androidx-startup"android:exported="false"tools:node="merge" ><meta-dataandroid:name="androidx.work.WorkManagerInitializer"android:value="androidx.startup" /></provider>......
</application>
说明:
- tools:node="merge" 用于多模块 Manifest 合并。
- android:name:配置组件初始化类的完整名称。
- android:value:固定为 "androidx.startup" 字符串。
3.3. 声明依赖关系
假设现在有两个库:Sdk1 与 Sdk2,其中 Sdk2 依赖 Sdk1。可按如下方式定义:
Sdk1Initializer:
class Sdk1Initializer : Initializer<Sdk1Manager> {override fun create(context: Context): Sdk1Manager {Sdk1Manager.initialize(context)return Sdk1Manager.getInstance()}override fun dependencies(): List<Class<out Initializer<*>?>?> {return Collections.emptyList()}
}
Sdk2Initializer:
class Sdk2Initializer : Initializer<Sdk2Manager> {override fun create(context: Context): Sdk2Manager {Sdk2Manager.initialize(context)return Sdk2Manager.getInstance()}override fun dependencies(): List<Class<out Initializer<*>?>?> {val dependencies: MutableList<Class<out Initializer<*>?>?> = ArrayList()dependencies.add(Sdk1Initializer::class.java)return dependencies}
}
Manifest 配置:
<application><providerandroid:name="androidx.startup.InitializationProvider"android:authorities="${applicationId}.androidx-startup"android:exported="false"tools:node="merge"><meta-dataandroid:name="com.zyx.app.startup.Sdk2Initializer"android:value="androidx.startup" /></provider>......
</application>
说明:
- Sdk2Initializer 的 dependencies() 已声明了依赖关系,App Startup 会自动识别执行顺序(先 Sdk1 再 Sdk2)。
- 即使 Sdk1Initializer 未出现在任何 <meta-data> 中,也会被自动加载。
- 若两者都配置了 <meta-data>,不会重复初始化,因为 App Startup 内部有缓存与拓扑排序机制,能确保每个组件只执行一次。
4. 取消组件自动初始化
某些场景下,我们可能不希望在应用启动时立即初始化所有组件。
例如,有些 SDK 在初始化时会访问敏感数据或申请权限,通常应在用户同意隐私政策后再执行。
此时可以禁用自动初始化并改为手动初始化。
4.1 禁用单个组件
可通过移除该组件的 <meta-data> 项来禁用自动初始化,例如:
<application><providerandroid:name="androidx.startup.InitializationProvider"android:authorities="${applicationId}.androidx-startup"android:exported="false"tools:node="merge"><meta-dataandroid:name="com.zyx.app.startup.Sdk2Initializer"tools:node="remove" /></provider>......
</application>
若想禁用所有组件的自动初始化,可移除整个 Provider:
<application><providerandroid:name="androidx.startup.InitializationProvider"android:authorities="${applicationId}.androidx-startup"android:exported="false"tools:node="remove"></provider>......
</application>
说明:
- tools:node="remove" 会在 Manifest 合并阶段移除对应节点。
- 禁用组件自动初始化后,系统不会再递归初始化其依赖。
4.2. 手动初始化组件
在需要时,可使用以下方式手动触发初始化:
AppInitializer.getInstance(context).initializeComponent(Sdk2Initializer::class.java)
此调用会自动递归初始化其依赖(例如 Sdk1),无需手动顺序控制。
5. Lint 检查
App Startup 提供了内置的 Lint 规则,可帮助检测初始化配置是否正确:
./gradlew :app:lintDebug
Lint 会检测并提示以下问题:
- 未注册的初始化器;
- 依赖循环;
- 无效的 <meta-data>;
- 未使用的初始化器。
6. 总结
App Startup 为 Android 提供了一种统一、简洁且高效的组件初始化方案。
它不仅减少了启动阶段的性能开销,还让依赖关系更清晰、初始化逻辑更可控。
无论是应用开发者还是 SDK 作者,都能从中获益。
更多详细的 App Startup 介绍,请访问 Android 开发者官网。