App Startup
是 Jetpack
的新成员,官方声明这是一个在 Android 应用启动时,针对初始化组件进行优化的依赖库,提供了一种在应用程序启动时初始化组件的简单、高效的方法。库开发者和应用开发者都可以使用app Startup来简化启动序列,并显式地设置初始化顺序。
App 启动初始化方式
Application.onCreate()
App 引用的库或SDK或其他组件,很多在使用前都需要进行初始化,这个过程一般会放在 Application
的 onCreate()
中,当需要初始化的组件越来越多时,可能会出现:
class MyApplication : Application() {
override fun onCreate() {
super.onCreate()
A.init(this)
B.init(this)
C.init(this)
D.init(this)
E.init(this)
}
...
}
当 init()
一连出现几十行时,会显得既凌乱又多余。
ContentProvider
ContentProvider
作为四大组件之一,主要作用是跨应用程序共享数据。它的 onCreate
调用在 Application.attachBaseContext()
和 Application.onCreate()
之间。所以库开发者们想到借助 ContentProvider
来进行初始化。
class MyProvider : ContentProvider() {
override fun onCreate(): Boolean {
context?.let {
A.init(it)
}
return true
}
...
}
继承 ContentProvider
并在 onCreate()
中完成初始化操作,然后在 AndroidManifest
中注册,那么当应用启动时,会自动调用这个 ContentProvider
的 onCreate()
从而完成初始化过程。这样使用者不再需要在 Application
显式写入初始化逻辑,也就是可对其“无感”。
但是这种方式存在性能问题,ContentProvider
作为四大组件之一,是相对比较重量级的,可能一个本身很轻量级的初始化过程,通过这种方式就会变成重量级操作,而如果有几十个这样的初始化需求,各自创建了一个 ContentProvider
会发生什么呢?
上图是 Google 官方的一个测试结果。一个空的 ContentProvider
大约会占用 2ms 的耗时,随着数量的增加,耗时也会跟着一起增加。如果使用了50个 ContentProvider
,那么将会占用接近 20ms 的耗时,这还只是空 ContentProvider
的耗时,并没有算上其中执行初始化逻辑的耗时。
所以 App Startup
其实就是为了解决这个问题诞生的。
App Startup
一句话总结:
App Startup
将所有用于初始化的 ContentProvider
合并成一个,从而使 App 的启动速度变得更快。
具体来说 App Startup
内部会创建了一个 ContentProvider
,并提供了一套用于初始化的标准。其他组件只需要都按照这套标准进行实现,就可以保证在 App 启动之前成功进行初始化并可自定义先后顺序。
App Startup 的使用
1、引入依赖
dependencies {
implementation "androidx.startup:startup-runtime:1.0.0"
}
2、定义 Initializer
// Initializes WorkManager.
class WorkManagerInitializer : Initializer {
override fun create(context: Context): WorkManager {
val configuration = Configuration.Builder().build()
WorkManager.initialize(context, configuration)
return WorkManager.getInstance(context)
}
override fun dependencies(): List>> {
// No dependencies on other libraries.
return emptyList()
}
}
如果 ExampleLogger
的初始化依赖于 WorkManager
的初始化:
// Initializes ExampleLogger.
class ExampleLoggerInitializer : Initializer {
override fun create(context: Context): ExampleLogger {
// WorkManager.getInstance() is non-null only after
// WorkManager is initialized.
return ExampleLogger(WorkManager.getInstance(context))
}
override fun dependencies(): List>> {
// Defines a dependency on WorkManagerInitializer so it can be
// initialized after WorkManager is initialized.
return listOf(WorkManagerInitializer::class.java)
}
}
3、注册 Provider
- 注意
android:name="com.example.ExampleLoggerInitializer"
这一条之外的内容都不要修改。 - 被已注册的
Initializer
所依赖的Initializer
可以不需要注册,如上的WorkManagerInitializer
。
4、手动初始化(延迟初始化)
如果不想在启动时自动初始化,而是在希望的地方才进行,可使用 AppInitializer
类手动实现延迟初始化:
AppInitializer.getInstance(this).initializeComponent(WorkManagerInitializer::class.java)
但前提是要禁止自动初始化:
tools:node="remove"
会在合并 AndroidManifest
时将 android:name
为 "com.example.ExampleLoggerInitializer"
的 meta-data
删除。
SuperApp引入
当前 IPCApplication
中也能看到不少初始化代码:
TPLog.init(IPCAppConstants.LOG_FILE_FOLDER_PATH, TPUtils.isApkInDebug(this));
......
RouterRepository.getInstance().init();
WeatherRepository.getInstance().init();
CommonProxy.getInstance().init();
DeviceProxy.getInstance().init();
CloudServiceProxy.getInstance().init();
......
SuperApp
会依赖许多 app-libs
的库,而且正在进行组件化拆分,各个库和功能组件应该会有许多有初始化需求,是可以考虑引入 App Startup
优化初始化管理的。每个库和组件实现自己的 Initializer
并在其中完成初始化,将相关逻辑保持在自己内部,更符合单一职责。然后注册到同一个 InitializationProvider
中,可以减少 IPCApplication
中的杂乱代码,有助于业务逻辑分离,让代码结构变得更加合理与清晰,新引入库或拆分出模块时也不需要去改动 IPCApplication
。同时引入也是非常简单。
但个人感觉这个组件其实并不是很有用,优点是很简单,缺点则是太简单了。最主要是没有一个异步的机制,如果某个初始化是需要异步的,App Startup
无法获知异步过程的结果,也无法根据异步结果处理依赖关系,它的依赖控制更像是一个同步队列,更不能做到多个初始化同时进行,全部完成后再进行某个初始化这样的复杂控制。而且现在我们 app 的初始化复杂度也不是太高,这个组件属于可有可无,有空再搞的一个优化方案。