持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第28天,点击查看活动详情
前言
在上篇文章中「初始化Library新姿势——App Startup」我们学会了 App Startup
的使用,下面我们接着学习 App Startup
的原理。
切入点
在学习原理之前,我们需要先找到切入点。
因为 ALibraryInitializer 是在 AndroidManifest.xml
中进行注册的,所以我们先看看注册信息:
<provider
android:name="androidx.startup.InitializationProvider"
android:authorities="${applicationId}.androidx-startup"
android:exported="false"
tools:node="merge">
<meta-data
android:name="com.bjsdm.testkotlin.ALibraryInitializer"
android:value="androidx.startup" />
</provider>
这是一个 ContentProvider
,而 ALibraryInitializer
只是 meta-data
里面的值而已,所以我们需要先看看 InitializationProvider
。
执行流程
我们先来看看 InitializationProvider
源码:
public class InitializationProvider extends ContentProvider {
@Override
public final boolean onCreate() {
Context context = getContext();
if (context != null) {
Context applicationContext = context.getApplicationContext();
if (applicationContext != null) {
AppInitializer.getInstance(context).discoverAndInitialize(); // <- 重点
} else {
StartupLogger.w("Deferring initialization because `applicationContext` is null.");
}
} else {
throw new StartupException("Context cannot be null");
}
return true;
}
}
InitializationProvider
的代码也很简单,除了 onCreate()
方法,其它方法都没有具体的实现,而在 onCreate(()
中,最核心的也只是这段:
AppInitializer.getInstance(context).discoverAndInitialize();
所以我们来看看 discoverAndInitialize()
做了什么:
void discoverAndInitialize() {
···
ComponentName provider = new ComponentName(mContext.getPackageName(),
InitializationProvider.class.getName());
ProviderInfo providerInfo = mContext.getPackageManager()
.getProviderInfo(provider, GET_META_DATA);
Bundle metadata = providerInfo.metaData;
discoverAndInitialize(metadata);
···
}
其实也就是获取配置中的 metaData
数据,然后传递给 discoverAndInitialize(metadata)
:
void discoverAndInitialize(@Nullable Bundle metadata) {
String startup = mContext.getString(R.string.androidx_startup);
···
if (metadata != null) {
Set<Class<?>> initializing = new HashSet<>();
Set<String> keys = metadata.keySet();
for (String key : keys) {
String value = metadata.getString(key, null);
if (startup.equals(value)) {
Class<?> clazz = Class.forName(key);
if (Initializer.class.isAssignableFrom(clazz)) {
Class<? extends Initializer<?>> component =
(Class<? extends Initializer<?>>) clazz;
mDiscovered.add(component);
···
}
}
}
···
for (Class<? extends Initializer<?>> component : mDiscovered) {
doInitialize(component, initializing);
}
}
···
}
主要作用就是在 metadata
中获取全部的 Initializer
数据,然后存储到 mDiscovered
中,然后对于 mDiscovered
进行遍历,调用 doInitialize
:
private <T> T doInitialize(
@NonNull Class<? extends Initializer<?>> component,
@NonNull Set<Class<?>> initializing) {
···
Object result;
if (!mInitialized.containsKey(component)) {
initializing.add(component);
try {
// 创建 Initializer
Object instance = component.getDeclaredConstructor().newInstance();
Initializer<?> initializer = (Initializer<?>) instance;
List<Class<? extends Initializer<?>>> dependencies =
initializer.dependencies();
// 判断是否先初始化 dependencies 的 Initializer
if (!dependencies.isEmpty()) {
for (Class<? extends Initializer<?>> clazz : dependencies) {
if (!mInitialized.containsKey(clazz)) {
doInitialize(clazz, initializing);
}
}
}
···
// 调用 initializer 的 create(),其实就是对于 initializer 的 SDK 进行初始化
result = initializer.create(mContext);
···
initializing.remove(component);
mInitialized.put(component, result);
}
···
} else {
result = mInitialized.get(component);
}
return (T) result;
···
}
主要逻辑:
- 创建 Initializer
- 判断是否先初始化 dependencies 的 Initializer
- 调用 initializer 的 create(),其实就是对于 initializer 的 SDK 进行初始化
至此,initializer 初始化 SDK 的行为就完成了。