目录
2.2.1、InitializationProvider的学习
一、使用:
二、学习源码:
2.1、总体源码学习介绍
如下图所示:就三个类我们需要关注,其中我们需要学习的是就是一个类AppInitializer
2.2、正式源码学习
2.2.1、InitializationProvider的学习
@Override
public boolean onCreate() {
Context context = getContext();
if (context != null) {
// 就干一件事情:发现并初始化Initializer
AppInitializer.getInstance(context).discoverAndInitialize();
} else {
throw new StartupException("Context cannot be null");
}
return true;
}
第一就是在ContentProvider中onCreate去调用主操作函数初始化Initializer,看源码可以看到一个重要信息:initializes them before {@link Application#onCreate()} 即会在Application一开始被调用。
所以我们的注意力集中在AppInitializer前先看一下接口Initializer吧
2.2.2、Initializer的学习
public interface Initializer<T> {
/**
* Initializes and a component given the application {@link Context}
*
* @param context The application context.
*/
@NonNull
T create(@NonNull Context context);
/**
* @return A list of dependencies that this {@link Initializer} depends on. This is
* used to determine initialization order of {@link Initializer}s.
* <br/>
* For e.g. if a {@link Initializer} `B` defines another
* {@link Initializer} `A` as its dependency, then `A` gets initialized before `B`.
*/
@NonNull
List<Class<? extends Initializer<?>>> dependencies();
}
泛型的接口,create方法需要返回你想要的类型,在这个函数中去做想要的初始化操作即可;
dependencies方法正如注释上说的:如果你定义一个myOneInitializer implements Initializer<Boolean> 但是你需要在初始myOneInitializer前还需要初始化一个myTwoInitializer implements Initializer<Object>,那么你就需要在dependencies中做依赖即new ArrayList().add(myTwoInitializer()),这个必须需要提供一个无参构造哦。
下面我们重点学习下AppInitializer是如何为我们注入操作的吧。
2.2.3、AppInitializer的学习(重点学习)
单例的学习,对的,AppInitializer是单例的。同步锁sLock
public static AppInitializer getInstance(@NonNull Context context) {
if (sInstance == null) {
synchronized (sLock) {
if (sInstance == null) {
sInstance = new AppInitializer(context);
}
}
}
return sInstance;
}
初始化处理重点关注两个全局变量:
final Set<Class<? extends Initializer<?>>> mDiscovered; // set集合收集初始化完毕的Initializer类
final Map<Class<?>, Object> mInitialized;// map以Initializer类为键,记得Initializer中的create的泛型吧,对就是它作为值
AppInitializer(@NonNull Context context) {
mContext = context.getApplicationContext();
mDiscovered = new HashSet<>();
mInitialized = new HashMap<>();
}
大家可能还有印象,我们InitializerProvider中可是调用了discoverAndInitialize函数,那么它做了什么操作呢?
void discoverAndInitialize() {
try {
Trace.beginSection(SECTION_NAME);
ComponentName provider = new ComponentName(mContext.getPackageName(),
InitializationProvider.class.getName());
ProviderInfo providerInfo = mContext.getPackageManager()
.getProviderInfo(provider, GET_META_DATA);
Bundle metadata = providerInfo.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);
if (StartupLogger.DEBUG) {
StartupLogger.i(String.format("Discovered %s", key));
}
doInitialize(component, initializing);
}
}
}
}
} catch (PackageManager.NameNotFoundException | ClassNotFoundException exception) {
throw new StartupException(exception);
} finally {
Trace.endSection();
}
}
先大致看一下,下面我一一学习分析下吧。
首先,获取Manifest.xml中的Provider的meta-data信息,先插补一下清单文件的核心点吧。
<provider
android:name="androidx.startup.InitializationProvider"
android:authorities="${applicationId}.androidx-startup"
android:exported="false"
tools:node="merge">
<!--使用者只需要添加meta_data的自己实现的Initializer,注意的是value必须是下面这个字符串,因为这个在实现时定死了,哈哈-->
<meta-data
android:name="com.qzx.ble.BleInitializer"
android:value="androidx.startup" />
</provider>
大家看到了tools:node="merge"标签了吧,这个时manifest的标签,用于manifes合并的处理,这个知识参见谷歌Android文档吧。所以我们第一步需要获取所有的InitializationProvider的所有meta-data的数据,然后去一一初始化。
// 创建要搜索的InitializationProvider的组件名对象
ComponentName provider = new ComponentName(mContext.getPackageName(),
InitializationProvider.class.getName());
// 拿到包管理器对象后按照meta-data标签获取内容提供者Provider的清单信息对象
ProviderInfo providerInfo = mContext.getPackageManager()
.getProviderInfo(provider, GET_META_DATA);
// 获取InitializationProvider下的所有meta-data的信息,用Bundle包装
Bundle metadata = providerInfo.metaData;
见注释,拿取到meta-data的Bundle类。
下面的代码可以看到,取的时keySet,那么即取得是所有我们要实现的Initializer的类的set集合,看到了吧,通过key发现value是否等于字符串‘androidx.startup’,如果这个条件满足了,创建Class对象,然后还去判断是否是继承于Initializer
Initializer.class.isAssignableFrom(clazz)
这个函数返回true,如果是一样的class,或者是Object对象的基本基础类型,以及继承、实现于其超类等,这个函数值得学习和使用,这里因为我们都是实现了Initializer的接口,所以会筛选出所有实现了Initalizer接口的实现类。然后去调用下一个重要的实现函数:doInitialize(component, initializing);在这里大家也看到了需要把这个class加入和hashset中,因为这里算是发现了一个Initializer了。
mDiscovered.add(component);
if (StartupLogger.DEBUG) {
StartupLogger.i(String.format("Discovered %s", key));
}
doInitialize(component, initializing);
在doInitialize中,先看源码如下:
<T> T doInitialize(
@NonNull Class<? extends Initializer<?>> component,
@NonNull Set<Class<?>> initializing) {
synchronized (sLock) {
boolean isTracingEnabled = Trace.isEnabled();
try {
...
if (initializing.contains(component)) {
String message = String.format(
"Cannot initialize %s. Cycle detected.", component.getName()
);
throw new IllegalStateException(message);
}
Object result;
if (!mInitialized.containsKey(component)) {
initializing.add(component);
try {
Object instance = component.getDeclaredConstructor().newInstance();
Initializer<?> initializer = (Initializer<?>) instance;
List<Class<? extends Initializer<?>>> dependencies =
initializer.dependencies();
if (!dependencies.isEmpty()) {
for (Class<? extends Initializer<?>> clazz : dependencies) {
if (!mInitialized.containsKey(clazz)) {
doInitialize(clazz, initializing);
}
}
}
if (StartupLogger.DEBUG) {
StartupLogger.i(String.format("Initializing %s", component.getName()));
}
result = initializer.create(mContext);
if (StartupLogger.DEBUG) {
StartupLogger.i(String.format("Initialized %s", component.getName()));
}
initializing.remove(component);
mInitialized.put(component, result);
} catch (Throwable throwable) {
throw new StartupException(throwable);
}
} else {
result = mInitialized.get(component);
}
return (T) result;
} finally {
Trace.endSection();
}
}
}
大家简单看一遍,首先从hashmap的mInitialized中去找是否已经初始化过了,如果没有走主要的逻辑了,看。
initializing.add(component);
try {
Object instance = component.getDeclaredConstructor().newInstance();
Initializer<?> initializer = (Initializer<?>) instance;
List<Class<? extends Initializer<?>>> dependencies =
initializer.dependencies();
if (!dependencies.isEmpty()) {
for (Class<? extends Initializer<?>> clazz : dependencies) {
if (!mInitialized.containsKey(clazz)) {
doInitialize(clazz, initializing);
}
}
}
...
result = initializer.create(mContext);
...
initializing.remove(component);
mInitialized.put(component, result);
} catch (Throwable throwable) {
throw new StartupException(throwable);
}
通过class类反射获取实现的Initialize的默认构造后创建相应的对象首先获取其dependencies(),结合上面说的,这个函数里面的Initialize是需要被先依赖进去的,所以,中间的for循环就是去先初始化所依赖的Initialize,同时初始化完毕塞入hashmap的mInitialized中。
值得注意的是doInitialize需要传递一个Set<class<?>>这个集合干的事就是一个,确保只会初始化一次Initialize,可见看到一开始 initializing.add(component); 创建后 initializing.remove(component);移除掉。
最后提一嘴:初始化依赖中用到了递归哦。