对于冷启动的App,我们知道其启动过程中,ContentProvidor是先于Applycation初始化的,在Android 10的源码中可以验证:
//ActivityThread.java
private void handleBindApplication(AppBindData data) {
//初始化ContentProvidor
if (!data.restrictedBackupMode) {
if (!ArrayUtils.isEmpty(data.providers)) {
installContentProviders(app, data.providers);
}
}
//初始化Applycation
try {
mInstrumentation.callApplicationOnCreate(app);
} catch (Exception e) {}
}
如果一个App定义了多个ContentProvider,也会遍历ContentProvider列表,循环初始化:
private void installContentProviders(
Context context, List<ProviderInfo> providers) {
final ArrayList<ContentProviderHolder> results = new ArrayList<>();
for (ProviderInfo cpi : providers) {
if (DEBUG_PROVIDER) {
StringBuilder buf = new StringBuilder(128);
buf.append("Pub ");
buf.append(cpi.authority);
buf.append(": ");
buf.append(cpi.name);
Log.i(TAG, buf.toString());
}
ContentProviderHolder cph = installProvider(context, null, cpi,
false /*noisy*/, true /*noReleaseNeeded*/, true /*stable*/);
if (cph != null) {
cph.noReleaseNeeded = true;
results.add(cph);
}
}
}
因此,如果一个App中定义了多个ContentProvider的话,就会影响冷启动的速度。AppStartUp正是为了解决多个ContentProvidor造成的冷启动时间长的问题,基本使用参考官方文档,其原理是使用系统的InitializationProvider来汇总所有的需要在其他ContentProvidor初始化的任务,其初始化方式有:
- 自动初始化;
- 主动初始化。
1. 自动初始化源码分析
AppStartUp所有功能的入口是InitializationProvider类的onCreate()函数:
//InitializationProvider.java
public boolean onCreate() {
Context context = getContext();
if (context != null) {
AppInitializer.getInstance(context).discoverAndInitialize();
} else {
throw new StartupException("Context cannot be null");
}
return true;
}
所有的自动初始化功能是AppInitializer单例的discoverAndInitialize()方法完成的:
void discoverAndInitialize() {
try {
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();
// 可以定义多个<meta-data>标签,每个标签中name不相同,value却是相同的
for (String key : keys) {
String value = metadata.getString(key, null);
//value必须等于"androidx.startup"
if (startup.equals(value)) {
Class<?> clazz = Class.forName(key);
if (Initializer.class.isAssignableFrom(clazz)) {
Class<? extends Initializer<?>> component =
(Class<? extends Initializer<?>>) clazz;
doInitialize(component, initializing);
}
}
}
}
} catch (PackageManager.NameNotFoundException | ClassNotFoundException exception) {}
}
这段代码就是根据解析的Manifest.xml文件中的<providor>标签下的<meta-data>的信息,来初始化metaData中name指定的类的,具体初始化每个Initializer子类的函数是doInitialize(),该函数也是主动初始化时调用的函数,在看这个函数的逻辑之前先看一下<meta-data>的定义:
<application>
<provider
android:name="androidx.startup.InitializationProvider"
android:authorities="${applicationId}.androidx-startup"
android:exported="false"
tools:node="merge">
<!-- 自动初始化 -->
<meta-data
android:name="com.hi.dhl.startup.library.LibaryX"
android:value="androidx.startup" />
</provider>
</application>
2. 主动初始化源码分析
假如我们想要在某个时机初始化某个类库的初始化类LibaryY,当然LibaryY是继承Initializer的,可以调用一下代码:
AppInitializer.getInstance(applicationContext)
.initializeComponent(LibaryY::class.java)
先看一下LibaryY的定义:
class LibaryY : Initializer<LibaryY.Dependency> {
override fun create(context: Context): Dependency {
return Dependency()
}
override fun dependencies(): MutableList<Class<out Initializer<*>>> {
return mutableListOf()
}
companion object {
private const val TAG = "LibaryY";
}
class Dependency {
init {
initializer = true
}
companion object {
var initializer: Boolean = false
}
}
}
Dependency内部类是用来包装初始化的代码的,dependencies()函数是用来添加其他的依赖的Initializer,初始化本类前会先初始化dependencies()函数中添加的的Initializer。下面看一下initializeComponent()函数的逻辑:
public <T> T initializeComponent(@NonNull Class<? extends Initializer<T>> component) {
return doInitialize(component, new HashSet<Class<?>>());
}
<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)) {
initializing.add(component);
try {
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需要初始化的内容
result = initializer.create(mContext);
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();
}
}
}