App Startup组件提供了简洁的、高效的方式用于App启动时的组件初始化。无论是Lib开发者还是App开发者都可以使用App Startup像流水线一样链式或者明确设置次序的初始化。
之前的做法是定义多个Provider组件,在每个Provider中分别对组件做初始化,App Startup可以让你在一个单个ContentProvider
中完成所有组件的初始化。这样做可以显著缩短App启动时间。
引入
为了使用Android Startup组件,按照如下方式在你的app/lib中build.gradle文件中引入依赖
dependencies {
implementation "androidx.startup:startup-runtime:1.0.0-alpha03"
}
App启动时初始化组件
在Apps/Libs初始化时,我们经常需要做一些三方组件的初始化或者已有组件的初始化。你可以使用多个ContentProvider初始化每个依赖来满足需求,但是多个ContentProviders的实例化会引起很大的性能开销以及托慢App启动速度。另外,Android初始化ContentProvider没有特定的顺序,可能会导致一些意想不到错误或异常。
App Startup提供了更高效的方式来初始化组件并且明确定义了它们之间的依赖关系。
为了使用App Startup自动完成组件的初始化,你必须为每个组件定义Initializer.
组件Initializers的实现
通过实现 Initializer<T>
接口来定义每个组件的Initializer
,该接口中定义了2个重要的方法:
- create()方法,包含所有初始化必要的操作,并且返回一个T实例。
- dependencies() 方法,返回一个
Initializer<T>
类型的列表,为该Initializer所依赖的Initializer。
你可以使用该方法控制组件初始化的顺序。
例如,你的App需要以来WorkManager
组件,你需要在App启动时初始化它。定义一个WorkManagerInitializer
,通过实现Initializer<WorkManager>
完成
// 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()
}
}
// Initializes WorkManager.
class WorkManagerInitializer implements Initializer<WorkManager> {
@Override
public WorkManager create(Context context) {
Configuration configuration = Configuration.Builder().build();
WorkManager.initialize(context, configuration);
return WorkManager.getInstance(context);
}
@Override
public List<Class<Initializer<?>>> dependencies() {
// No dependencies on other libraries.
return emptyList();
}
}
dependencies()
方法返回一个空列表因为WorkManager
不依赖于其他的Libs
假如你的App还依赖一个叫做ExampleLogger
的Lib,该Lib依赖WorkManager Lib。这种依赖关系意味着你需要确保App先初始化WorkManager
,定义ExampleLoggerInitializer
类,该类实现了Initializer<ExampleLogger>
接口。
// Initializes ExampleLogger.
class ExampleLoggerInitializer : Initializer<ExampleLogger> {
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<Class<out Initializer<*>>> {
// Defines a dependency on WorkManagerInitializer so it can be
// initialized after WorkManager is initialized.
return listOf(WorkManagerInitializer::class.java)
}
}
// Initializes ExampleLogger.
class ExampleLoggerInitializer implements Initializer<ExampleLogger> {
@Override
public ExampleLogger create(Context context) {
// WorkManager.getInstance() is non-null only after
// WorkManager is initialized.
return ExampleLogger(WorkManager.getInstance(context));
}
@Override
public List<Class<Initializer<?>>> dependencies() {
// Defines a dependency on WorkManagerInitializer so it can be
// initialized after WorkManager is initialized.
return Arrays.asList(WorkManagerInitializer.class);
}
}
因为你在dependencies()
方法中包含了WorkManagerInitializer
,App启动时,会先初始化WorkManager
,然后再初始化ExampleLogger
。
在manifest添加入口
App Startup包含一个名为InitializationProvider
的内容提供者,用于发现并调用你的组件initializers.App Startup通过<meta-data>
标签发现组件的Initializers。然后,App Startup调用dependencies()
方法来启动其依赖的一系列Initializers。
为了确保组件被发现,下列条件必须满足:
1.该组件Initializer在InitializationProvider
下必须有<meta-data>
标签声明。
2.该组件Initializer必须保证在其dependencies()
方法中的Initializer列表可以被发现的。
再次考虑样例中的WorkManagerInitializer
和 ExampleLoggerInitializer
。为了确保App Startup可以发现这些initializers,必须在manifest中添加如下代码:
<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>
你不需要为WorkManagerInitializer添加<meta-data>
标签,因为WorkManagerInitializer已经是ExampleLoggerInitializer
的一个依赖。这就意味着如果ExampleLoggerInitializer
被发现了,那么WorkManagerInitializer
也是可以被发现的。
tools:node="merge"
属性确保manifest的merger工具可以解决实体冲突。
运行lint工具检查
为了检查你是否正确使用了App Startup组件,可以运行./gradlew :app:lintDebug命令来校验。
手动启动组件
通常当你使用App Startup时,InitializationProvider
使用一个名为AppInitializer
的组件来自动发现并运行你的initializers组件。然而,你也可以使用AppInitializer
来手动启动这些初始化组件,这叫做懒加载,可以帮助你减少启动消耗。
如果你要手动初始化,不需要首先关闭自动初始化功能。
关闭单个组件的自动初始化
为了关闭单个组件的自动初始化,移除该组件的标签。
例如,添加如下代码到manifest中关闭ExampleLogger的初始化:
<provider
android:name="androidx.startup.InitializationProvider"
android:authorities="${applicationId}.androidx-startup"
android:exported="false"
tools:node="merge">
<meta-data android:name="com.example.ExampleLoggerInitializer"
tools:node="remove" />
</provider>
使用tools:node="remove"
标签而不是简单的删掉整个meta-data
标签是为了确保merger工具可以移除所有其他merged manifest文件中的该组件。
关闭所有组件的自动初始化
为了关闭组件初始化功能,将InitializationProvider
标签从manifetst中移除,代码如下
<provider
android:name="androidx.startup.InitializationProvider"
android:authorities="${applicationId}.androidx-startup"
tools:node="remove" />
手动调用组件 initializers
如果组件的自动初始化功能关闭了,你可以使用AppInitializer来手动初始化该组件以及它所依赖的组件。
AppInitializer.getInstance(context)
.initializeComponent(ExampleLoggerInitializer::class.java)
AppInitializer.getInstance(context)
.initializeComponent(ExampleLoggerInitializer.class);
调用结果是,App Startup也会初始化WorkManager,因为WorkManager是ExampleLogger的一个依赖。