Startup源码解析
源码版本:
- Startup:1.1.0
导航:
使用
实现Initializer
class WorkManagerInitializer : Initializer<WorkManager> {
override fun create(context: Context): WorkManager {
// 初始化WorkManager
val configuration = Configuration.Builder().build()
WorkManager.initialize(context, configuration)
// 返回WorkManager初始化后的实例,以便通过AppInitializer.getInstance(context).initializeComponent(WorkManagerInitializer::class.java)初始化并获取。
return WorkManager.getInstance(context)
}
override fun dependencies(): List<Class<out Initializer<*>>> {
// 无依赖其它库
return emptyList()
}
}
因为WorkManager不依赖于任何其它库,所以该dependencies()方法返回一个空列表。
class ExampleLoggerInitializer : Initializer<ExampleLogger> {
override fun create(context: Context): ExampleLogger {
// 初始化ExampleLogger,并返回其对象,以便通过AppInitializer.getInstance(context).initializeComponent(ExampleLoggerInitializer::class.java)初始化并获取。
return ExampleLogger(WorkManager.getInstance(context))
}
override fun dependencies(): List<Class<out Initializer<*>>> {
// 依赖WorkManagerInitializer
return listOf(WorkManagerInitializer::class.java)
}
}
因为ExampleLogger依赖于WorkManager,所以该dependencies()方法返回包含WorkManagerInitializer的列表,使其在它之前初始化。
初始化Initializer
自动初始化组件
在清单文件中添加
<provider
android:name="androidx.startup.InitializationProvider"
android:authorities="${applicationId}.androidx-startup"
android:exported="false"
tools:node="merge">
<meta-data
android:name="com.example.ExampleLoggerInitializer" // 要初始化的Initializer类名全路径
android:value="androidx.startup" />
</provider>
自动初始化组件,其为在应用启动时初始化组件。不需要为WorkManagerInitializer添加<meta-data>条目,因为它是ExampleLoggerInitializer的依赖项,当然声明了也不会有问题(因为已经被初始了,则不会再进行初始化了,详细看源码介绍)。
说明:
- 该
provider的声明格式固定,只需要修改<meta-data>的name即可。- 该
<meta-data>的顺序,决定着初始化的顺序。- 该
tools:node="merge"属性确保清单合并工具正确解决任何冲突条目。
手动初始化组件
手动初始化组件,其意为就是不自动初始化组件,所以您必须禁用自动初始化,其又称为延迟初始化。
禁用单个组件的自动初始化
<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>上即可,其它保持不变。
说明:
- 如果
<meta-data>是自己的(可修改),则删除指定的<meta-data>即可;如果<meta-data>不是自己的(如三方库,不可修改),则使用tools:node="remove"声明即可。- 禁用组件的自动初始化也会禁用该组件的依赖项的自动初始化。
tools:node="remove",从合并后的清单中移除此元素。
禁用所有组件的自动初始化
<provider
android:name="androidx.startup.InitializationProvider"
android:authorities="${applicationId}.androidx-startup"
tools:node="remove" />
禁用所有组件的自动初始化,将tools:node="remove"声明到InitializationProvider的provider上即可,其它保持不变或删除掉全部<meta-data>都可以。
说明:
- 不推荐禁用所有组件的自动初始化,因为会禁用掉所有使用
startup库初始化的三方库(如lifecycle库的ProcessLifecycleInitializer),导致得需要手动初始化所有使用startup库的三方库,不方便后续维护。
手动初始化组件
val result = AppInitializer.getInstance(context)
.initializeComponent(ExampleLoggerInitializer::class.java)
手动初始化组件,调用AppInitializer.initializeComponent()方法即可,以上代码手动初始化ExampleLogger,又因为ExampleLogger依赖WorkManager,所以WorkManager也完成了初始化。
说明:
- 其返回值
result为ExampleLoggerInitializer的create()方法返回的ExampleLogger实例。- 如果
AppInitializer.initializeComponent()方法初始化的Initializer已经初始化完成,再次调用则不会再次初始化,而是会返回第一次初始化的结果值(如初始化ExampleLoggerInitializer,始终会返回第一次初始化的ExampleLogger实例)。
源码
实现Initializer
Initializer类
public interface Initializer<T> {
// 给定应用程序上下文初始化组件
@NonNull
T create(@NonNull Context context);
// 这个Initializer依赖的依赖项列表。这是用来确定Initializer的初始化顺序。
// 例如,如果一个初始化器 B 定义了另一个初始化器 A 作为它的依赖,那么 A 在 B 之前被初始化。
@NonNull
List<Class<? extends Initializer<?>>> dependencies();
}
Initializer类,为初始化器接口,这个接口定义了两个重要的方法:
-
create()方法,它包含初始化组件所需的所有操作,并返回T的实例。 -
dependencies()方法,它返回Initializer所依赖的其它Initializer<T>对象的列表。您可以使用此方法控制app在启动时运行initializers的顺序。
初始化Initializer
自动初始化组件
我们先来看一下startup库的清单文件
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="androidx.startup" >
<uses-sdk
android:minSdkVersion="14"
android:targetSdkVersion="30" />
<application>
<provider
android:name="androidx.startup.InitializationProvider"
android:authorities="${applicationId}.androidx-startup"
android:exported="false"
tools:node="merge" />
</application>
</manifest>
里面声明了最小SDK版本为14,以及声明了一个ContentProvider,它是InitializationProvider,接下来我们再来看一下InitializationProvider类。
InitializationProvider类
public class InitializationProvider extends ContentProvider {
@Override
public final boolean onCreate() {
Context context = getContext();
if (context != null) {
AppInitializer.getInstance(context).discoverAndInitialize();
} else {
throw new StartupException("Context cannot be null");
}
return true;
}
@Nullable
@Override
public final Cursor query(
@NonNull Uri uri,
@Nullable String[] projection,
@Nullable String selection,
@Nullable String[] selectionArgs,
@Nullable String sortOrder) {
throw new IllegalStateException("Not allowed.");
}
@Nullable
@Override
public final String getType(@NonNull Uri uri) {
throw new IllegalStateException("Not allowed.");
}
@Nullable
@Override
public final Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
throw new IllegalStateException("Not allowed.");
}
@Override
public final int delete(
@NonNull Uri uri,
@Nullable String selection,
@Nullable String[] selectionArgs) {
throw new IllegalStateException("Not allowed.");
}
@Override
public final int update(
@NonNull Uri uri,
@Nullable ContentValues values,
@Nullable String selection,
@Nullable String[] selectionArgs) {
throw new IllegalStateException("Not allowed.");
}
}
InitializationProvider类,它是一个ContentProvider,在其onCreate()方法里面调用了AppInitializer.getInstance(context).discoverAndInitialize(),我们先来看一下AppInitializer.getInstance(context)方法,然后再看一下其discoverAndInitialize()方法。
说明:
Application、ContentProvider、Activity的onCreate()执行顺序:Application.attachBaseContext()->ContentProvider.onCreate()->Application.onCreate()->Activity.onCreate()。
AppInitializer --> getInstance方法
public final class AppInitializer {
// 单例AppInitializer实例
private static volatile AppInitializer sInstance;
// 获取单例AppInitializer的实例
@NonNull
@SuppressWarnings("UnusedReturnValue")
public static AppInitializer getInstance(@NonNull Context context) {
if (sInstance == null) {
synchronized (sLock) {
if (sInstance == null) {
sInstance = new AppInitializer(context);
}
}
}
return sInstance;
}
}
AppInitializer.getInstance(context)方法,为单例获取AppInitializer的实例。
AppInitializer --> discoverAndInitialize方法
public final class AppInitializer {
// Tracing
private static final String SECTION_NAME = "Startup";
// 已发现Initializer的Set集合,value为Initializer的class。
@NonNull
final Set<Class<? extends Initializer<?>>> mDiscovered;
// 发现并初始化
@SuppressWarnings("unchecked")
void discoverAndInitialize() {
try {
Trace.beginSection(SECTION_NAME);
// 获取InitializationProvider的ProviderInfo
ComponentName provider = new ComponentName(mContext.getPackageName(),
InitializationProvider.class.getName());
ProviderInfo providerInfo = mContext.getPackageManager()
.getProviderInfo(provider, GET_META_DATA);
// 获取<meta-data>信息
Bundle metadata = providerInfo.metaData;
// 获取字符串,值为"androidx.startup"
String startup = mContext.getString(R.string.androidx_startup);
// 判断metadata为不为null,即有没有配置<meta-data>,没配置则不处理。
if (metadata != null) {
// 初始化中Initializer的Class集合
Set<Class<?>> initializing = new HashSet<>();
// 获取metadata中所有的key,即获取所有<meta-data>内的android:name。
Set<String> keys = metadata.keySet();
// 遍历metadata中所有的key
for (String key : keys) {
// 获取metadata中的值,即获取<meta-data>内的android:value。
String value = metadata.getString(key, null);
// 判断<meta-data>内的android:value为"androidx.startup"
if (startup.equals(value)) {
// 获取<meta-data>内的android:name指定的class
Class<?> clazz = Class.forName(key);
// 判断<meta-data>内的android:name指定的class是否是Initializer的子类。
if (Initializer.class.isAssignableFrom(clazz)) {
// 是Initializer子类,则强转。
Class<? extends Initializer<?>> component =
(Class<? extends Initializer<?>>) clazz;
// 添加到mDiscovered(已发现)集合
mDiscovered.add(component);
// 打印日志
if (StartupLogger.DEBUG) {
StartupLogger.i(String.format("Discovered %s", key));
}
// 初始化component,即初始化<meta-data>内的android:name指定的class。
doInitialize(component, initializing);
}
}
}
}
} catch (PackageManager.NameNotFoundException | ClassNotFoundException exception) {
throw new StartupException(exception);
} finally {
Trace.endSection();
}
}
}
AppInitializer.discoverAndInitialize()方法,为发现并初始化Initializer,找到清单文件配置的所有Initializer,然后调用doInitialize()方法进行初始化操作。
说明:
<meta-data>内的android:value,必须为androidx.startup。<meta-data>内的android:name,必须为Initializer子类的类名全路径。- 在清单文件配置的所有
Initializer,都会添加到mDiscovered(已发现)集合。
我们再来看一下AppInitializer.doInitialize()方法。
AppInitializer --> doInitialize方法
public final class AppInitializer {
// 线程锁
private static final Object sLock = new Object();
// 已经初始化Initializer的Map集合,key为Initializer的class,value为Initializer.onCreate()方法的返回值。
@NonNull
final Map<Class<?>, Object> mInitialized;
// 做初始化
@NonNull
@SuppressWarnings({"unchecked", "TypeParameterUnusedInFormals"})
<T> T doInitialize(
@NonNull Class<? extends Initializer<?>> component,
@NonNull Set<Class<?>> initializing) {
// 同步,保证线程安全。
synchronized (sLock) {
boolean isTracingEnabled = Trace.isEnabled();
try {
if (isTracingEnabled) {
// Use the simpleName here because section names would get too big otherwise.
Trace.beginSection(component.getSimpleName());
}
// 如果这个类正在初始化中,再初始化,则抛出异常。
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)) {
// 没初始化过,则进行初始化,并记录其create的结果。
// 添加到正在初始化中的集合,标记正在初始化中。
initializing.add(component);
try {
// 反射创建对象
Object instance = component.getDeclaredConstructor().newInstance();
// 强转,因为component实现了Initializer,所以没问题。
Initializer<?> initializer = (Initializer<?>) instance;
// 获取其依赖的Initializer列表
List<Class<? extends Initializer<?>>> dependencies =
initializer.dependencies();
// 如果其依赖的Initializer列表不为空,就先初始化列表。
if (!dependencies.isEmpty()) {
// 遍历其依赖的Initializer列表
for (Class<? extends Initializer<?>> clazz : dependencies) {
// 判断其依赖的Initializer,是否已经被初始化过。
if (!mInitialized.containsKey(clazz)) {
// 没初始化过,则进行递归初始化。
// -说明:在此会等待所有依赖完成才会执行后续代码。
doInitialize(clazz, initializing);
}
}
}
// 打印日志:初始化中的组件名。
if (StartupLogger.DEBUG) {
StartupLogger.i(String.format("Initializing %s", component.getName()));
}
// 调用create()方法进行初始化,并记录其返回结果。
result = initializer.create(mContext);
// 打印日志:初始化完成的组件名。
if (StartupLogger.DEBUG) {
StartupLogger.i(String.format("Initialized %s", component.getName()));
}
// 在正在初始化中的集合中移除,标记已经初始化过。
initializing.remove(component);
// 存入已经初始化的Initializer,以及其create()方法返回的结果。
mInitialized.put(component, result);
} catch (Throwable throwable) {
throw new StartupException(throwable);
}
} else {
// 已经初始化过,则获取其create()的结果。
result = mInitialized.get(component);
}
// 返回initializer.create()的结果
return (T) result;
} finally {
Trace.endSection();
}
}
}
}
AppInitializer.doInitialize()方法,为真正的初始化Initializer的方法,它反射创建Initializer对象,并调用其create()方法通知内部的初始化,并返回其create()方法的返回值。
说明:
- 如果这个
Initializer未被初始化,则反射创建这个Initializer对象,并调用其create()方法通知内部的初始化,并将其create()方法的结果添加到在mInitialized中以便后续获取;否则,则从mInitialized中获取第一次初始化的结果值,使其不会频繁创建这个Initializer对象。- 如果要创建的
Initializer,依赖其它Initializer,则会进行循环递归初始化其它Initializer,使其它Initializer全部初始化完成,才会执行此Initializer的create()方法。doInitialize()方法,因为使用了synchronized代码块,且锁sLock为静态的(唯一),所以当有线程正在执行doInitialize()方法时,其它线程再执行doInitialize()方法时都得等待上个线程执行完成。
手动初始化组件
AppInitializer --> initializeComponent方法
// 初始化Initializer类
@NonNull
@SuppressWarnings("unused")
public <T> T initializeComponent(@NonNull Class<? extends Initializer<T>> component) {
return doInitialize(component, new HashSet<Class<?>>());
}
AppInitializer.initializeComponent()方法,直接调用了doInitialize()方法进行创建,并返回了其doInitialize()方法的结果值(即Initializer.create()方法的返回值)。
说明:
- 只有
initializeComponent()方法才能拿到Initializer的create()方法的返回值,不管是自动初始化(ContentProvider)存入,还是手动初始化(调用initializeComponent())存入,都可以再次调用initializeComponent()方法获取到其在create()方法的返回值。- 由于
doInitialize()方法,使用了synchronized,导致其执行中,其它都得等待。例如:A、B耗时所以分别在一个子线程执行initializeComponent()方法,C在主线程执行,使其三个分别在三个线程执行,以达到并发的效果,但是结果为:A执行中,B等待A执行完成,C等待A、B执行完成,未达到并发效果。
其它源码
AppInitializer --> isEagerlyInitialized方法
// Initializer是否是被急切地初始化
public boolean isEagerlyInitialized(@NonNull Class<? extends Initializer<?>> component) {
// 如果从未调用过discoverAndInitialize(),则没有急于初始化任何内容。
return mDiscovered.contains(component);
}
AppInitializer.isEagerlyInitialized()方法,为Initializer是否是被急切地初始化,即是否是在清单文件配置中。
优缺点
优点
- 提供了一个规则,可以让所有的三方库,使用同一个
ContentProvider在其库内部进行初始化,减少了初始化代码且优化了创建多个ContentProvider造成的性能、时间损耗。 - 支持初始化的顺序以及依赖关系。
缺点
- 不支持多线程并发初始化。
- 反射创建
Initializer类,对性能有稍微影响。
总结
以上就是全面的Jetpack-Startup源码了!之后会出Jetpack其它源码系列,请及时关注。如果你有什么问题,大家评论区见!
最后推荐一下我的网站,开发者的技术博客: devbolg.cn ,目前包含android相关的技术,之后会面向全部开发者,欢迎大家来体验!