应用启动优化—App Startup
一、简介
App Startup 是 Android Jetpack 家族的成员,提供了一种在应用程序启动时,简单、高效的初始化组件的方法。无论是App开发人员,还是Library开发人员都可以使用App Startup来简化启动过程,并显式地设置初始化顺序。
App Startup 不需要为每个组件的初始化定义单独的 ContentProvider,它提供了一个 ContentProvider 来运行所有依赖项的初始化,从而显著的提高了应用程序的启动速度。
二、已知手段
- 在 Application 中做初始化:利用异步延迟初始化,或者延迟到 Activity 中初始化。
- 在 ContentProvider 中做初始化:在 Application 的 onCreate 方法之前执行。
- 阿里巴巴开源的 Alpha:基于PERT图构建的异步启动框架。
- 自定义启动器 做初始化:基于有向无环图拓扑排序的启动框架。
三、如何使用
1. 添加依赖
implementation "androidx.startup:startup-runtime:1.0.0-alpha02"
2. 实现Initializer<T>接口
public class Sdk4Initializer implements Initializer<Sdk4> {
@NonNull
@Override
public Sdk4 create(@NonNull Context context) {
// 执行初始化逻辑
Sdk4.getInstance().init(context);
return Sdk4.getInstance();
}
@NonNull
@Override
public List<Class<? extends Initializer<?>>> dependencies() {
List<Class<? extends Initializer<?>>> dependencies = new ArrayList<>();
// 添加初始化依赖项
dependencies.add(Sdk1Initializer.class);
dependencies.add(Sdk2Initializer.class);
return dependencies;
}
}
3. 注册AndroidManifest配置
<provider
android:name="androidx.startup.InitializationProvider"
android:authorities="${applicationId}.androidx-startup"
android:exported="false"
tools:node="merge">
<meta-data
android:name="com.example.demo.appstartup.Sdk1Initializer"
android:value="@string/androidx_startup" />
<meta-data
android:name="com.example.demo.appstartup.Sdk3Initializer"
android:value="@string/androidx_startup"
tools:node="remove" />
<meta-data
android:name="com.example.demo.appstartup.Sdk5Initializer"
android:value="@string/androidx_startup"
tools:node="remove" />
</provider>
- tools:node="merge"
在没有冲突的情况下,使用合并冲突启发式算法,合并此标记中的所有属性以及所有嵌套元素。它是节点合并的默认模式。
- tools:node="remove"
从合并后的清单中移除此元素。此标记在provider标签下,将禁用所有组件初始化;在meta-data标签下,将禁用单个组件初始化。
- android:value="xxx"
这里必须指定为字符串androidx_startup的值,否则声明的组件不生效。
4. 延迟初始化
<meta-data
android:name="com.example.demo.appstartup.Sdk5Initializer"
android:value="@string/androidx_startup"
tools:node="remove" />
// 手动执行初始化逻辑
AppInitializer.getInstance(getApplicationContext()).initializeComponent(Sdk5Initializer.class);
规律:
a. 不声明meta-data标签,自动初始化失效,手动初始化依然可以生效
b. 声明meta-data标签,且添加了tools:node="remove",自动初始化失效,手动初始化依然可以生效
c. 不声明meta-data标签,自动初始化失效;若做为依赖项,其他组件初始化之前,初始化依然可以生效
d. 声明meta-data标签,且添加了tools:node="remove";若做为依赖项,其他组件初始化之前,初始化依然可以生效
四、原理简析
1. 代码结构
2. 设计思路
- 使用 InitializationProvider 管理多个初始化项,避免创建多个 ContentProvider 做初始化,减少初始化耗时,提升 APP 的启动速度
- 通过实现 Initializer<T> 接口,设置初始化的依赖项,自定义组件间的初始化顺序
- 通过 Android tools 命名空间,配置组件是否自动初始化
- 支持延迟初始化,即手动初始化
3. 核心类
1) Initializer
public interface Initializer<T> {
/**
* 初始化
*/
@NonNull
T create(@NonNull Context context);
/**
* 设置依赖项,用于初始化顺序
*/
@NonNull
List<Class<? extends Initializer<?>>> dependencies();
}
2) InitializationProvider
public final class InitializationProvider extends ContentProvider {
/**
* 扫描和初始化AndroidManifest中配置的组件
*/
@Override
public boolean onCreate() {
Context context = getContext();
if (context != null) {
AppInitializer.getInstance(context).discoverAndInitialize();
} else {
throw new StartupException("Context cannot be null");
}
return true;
}
...
}
3) AppInitializer
public final class AppInitializer {
private static final String SECTION_NAME = "Startup";
private static volatile AppInitializer sInstance;
private static final Object sLock = new Object();
// 缓存已经初始化过的组件信息
@NonNull
final Map<Class<?>, Object> mInitialized;
@NonNull
final Context mContext;
AppInitializer(@NonNull Context context) {
mContext = context.getApplicationContext();
mInitialized = new HashMap<>();
}
@NonNull
@SuppressWarnings("UnusedReturnValue")
public static AppInitializer getInstance(@NonNull Context context) {
if (sInstance == null) {
synchronized (sLock) {
if (sInstance == null) {
sInstance = new AppInitializer(context);
}
}
}
return sInstance;
}
/**
* 用于延迟初始化(手动初始化)指定的组件
*/
@NonNull
@SuppressWarnings("unused")
public <T> T initializeComponent(@NonNull Class<? extends Initializer<T>> component) {
return doInitialize(component, new HashSet<Class<?>>());
}
@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) {
Trace.beginSection(component.getSimpleName());
}
// initializing存储正在初始化的组件,这里为了处理循环依赖问题
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()));
}
// 调用组件的create方法,执行具体的初始化逻辑
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();
}
}
}
/**
* 用于自动初始化
*/
@SuppressWarnings("unchecked")
void discoverAndInitialize() {
try {
Trace.beginSection(SECTION_NAME);
// 读取AndroidManifest文件, 获取InitializationProvider对应的meta-data标签信息
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);
// 遍历meta-data标签信息,获取Initializer实现类信息,然后进行初始化
if (metadata != null) {
Set<Class<?>> initializing = new HashSet<>();
Set<String> keys = metadata.keySet();
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;
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();
}
}
}
参考:
https://developer.android.google.cn/topic/libraries/app-startup
https://www.jianshu.com/p/f0902a219951
本文地址:https://blog.csdn.net/ecjtuhq/article/details/107851773