Startup源码解析
源码版本:
- Startup:1.1.0
导航:
- Jetpack-Lifecycle源码解析
- Jetpack-LiveData源码解析
- Jetpack-ViewModel源码详解
- Jetpack-Startup源码详解
- 更多的文章看这里:主页
使用
实现Initializer
class WorkManagerInitializer : Initializer {
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>> {
// 无依赖其它库
return emptyList()
}
}
因为WorkManager
不依赖于任何其它库,所以该dependencies(
)方法返回一个空列表。
class ExampleLoggerInitializer : Initializer {
override fun create(context: Context): ExampleLogger {
// 初始化ExampleLogger,并返回其对象,以便通过AppInitializer.getInstance(context).initializeComponent(ExampleLoggerInitializer::class.java)初始化并获取。
return ExampleLogger(WorkManager.getInstance(context))
}
override fun dependencies(): List>> {
// 依赖WorkManagerInitializer
return listOf(WorkManagerInitializer::class.java)
}
}
因为ExampleLogger
依赖于WorkManager
,所以该dependencies(
)方法返回包含WorkManagerInitializer
的列表,使其在它之前初始化。
初始化Initializer
自动初始化组件
在清单文件中添加
自动初始化组件,其为在应用启动时初始化组件。不需要为WorkManagerInitializer
添加
条目,因为它是ExampleLoggerInitializer
的依赖项,当然声明了也不会有问题(因为已经被初始了,则不会再进行初始化了,详细看源码介绍)。
说明:
- 该
provider
的声明格式固定,只需要修改的
name
即可。- 该
的顺序,决定着初始化的顺序。
- 该
tools:node="merge"
属性确保清单合并工具正确解决任何冲突条目。
手动初始化组件
手动初始化组件,其意为就是不自动初始化组件,所以您必须禁用自动初始化,其又称为延迟初始化。
禁用单个组件的自动初始化
禁用单个组件的自动初始化,将tools:node="remove"
声明到指定
上即可,其它保持不变。
说明:
- 如果
是自己的(可修改),则删除指定的
即可;如果
不是自己的(如三方库,不可修改),则使用
tools:node="remove"
声明即可。- 禁用组件的自动初始化也会禁用该组件的依赖项的自动初始化。
tools:node="remove"
,从合并后的清单中移除此元素。
禁用所有组件的自动初始化
禁用所有组件的自动初始化,将tools:node="remove"
声明到InitializationProvider
的provider
上即可,其它保持不变或删除掉全部
都可以。
说明:
- 不推荐禁用所有组件的自动初始化,因为会禁用掉所有使用
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 {
// 给定应用程序上下文初始化组件
@NonNull
T create(@NonNull Context context);
// 这个Initializer依赖的依赖项列表。这是用来确定Initializer的初始化顺序。
// 例如,如果一个初始化器 B 定义了另一个初始化器 A 作为它的依赖,那么 A 在 B 之前被初始化。
@NonNull
List>> dependencies();
}
Initializer
类,为初始化器接口,这个接口定义了两个重要的方法:
-
create()
方法,它包含初始化组件所需的所有操作,并返回T的实例。 -
dependencies()
方法,它返回Initializer
所依赖的其它Initializer
对象的列表。您可以使用此方法控制app
在启动时运行initializers
的顺序。
初始化Initializer
自动初始化组件
我们先来看一下startup
库的清单文件
里面声明了最小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>> 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);
// 获取信息
Bundle metadata = providerInfo.metaData;
// 获取字符串,值为"androidx.startup"
String startup = mContext.getString(R.string.androidx_startup);
// 判断metadata为不为null,即有没有配置,没配置则不处理。
if (metadata != null) {
// 初始化中Initializer的Class集合
Set> initializing = new HashSet<>();
// 获取metadata中所有的key,即获取所有内的android:name。
Set keys = metadata.keySet();
// 遍历metadata中所有的key
for (String key : keys) {
// 获取metadata中的值,即获取内的android:value。
String value = metadata.getString(key, null);
// 判断内的android:value为"androidx.startup"
if (startup.equals(value)) {
// 获取内的android:name指定的class
Class> clazz = Class.forName(key);
// 判断内的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,即初始化内的android:name指定的class。
doInitialize(component, initializing);
}
}
}
}
} catch (PackageManager.NameNotFoundException | ClassNotFoundException exception) {
throw new StartupException(exception);
} finally {
Trace.endSection();
}
}
}
AppInitializer.discoverAndInitialize()
方法,为发现并初始化Initializer
,找到清单文件配置的所有Initializer
,然后调用doInitialize()
方法进行初始化操作。
说明:
内的
android:value
,必须为androidx.startup
。内的
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, Object> mInitialized;
// 做初始化
@NonNull
@SuppressWarnings({"unchecked", "TypeParameterUnusedInFormals"})
T doInitialize(
@NonNull Class extends Initializer>> component,
@NonNull Set> 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>> 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 initializeComponent(@NonNull Class extends Initializer> component) {
return doInitialize(component, new HashSet>());
}
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相关的技术,之后会面向全部开发者,欢迎大家来体验!