办法一:运用 Application#onCreate
进行初始化
运用办法
- 自定义
CustomApplication
class CustomApplication : Application() {
// ..
override fun onCreate() {
super.onCreate()
// 进行组件初始化
}
// ..
}
- 在
主module
清单文件中声明运用CustomApplication
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<!-- ... -->
<application android:name="CustomApplication全途径或许相关于资源的途径">
<!-- ... -->
</application>
</manifest>
优缺陷
- 长处:简单易用,只需在
主module
的Application#onCreate
进行组件初始化,而且能够指定组件间初始化次序; - 缺陷:在其他
主module
运用的时候,需要在本身Application#onCreate
进行一遍初始化(对应组件依靠方来说,较为繁琐);同时假如组件存在依靠联系,运用方要清楚组件之间的联系,然后确认组件初始化次序,添加组件运用本钱;
办法二:运用 Content Provider
进行初始化
运用办法
- 自定义
ContentProvider
class CustomProvider : ContentProvider() {
override fun onCreate(): Boolean {
// 初始化组件
return true
}
override fun query(
uri: Uri,
projection: Array<out String>?,
selection: String?,
selectionArgs: Array<out String>?,
sortOrder: String?
): Cursor? = null
override fun getType(uri: Uri): String? = null
override fun insert(uri: Uri, values: ContentValues?): Uri? = null
override fun delete(uri: Uri, selection: String?, selectionArgs: Array<out String>?): Int = 0
override fun update(uri: Uri, values: ContentValues?, selection: String?, selectionArgs: Array<out String>?
): Int = 0
}
- 自定义
ContentProvider
在当时组件AndroidManifest.xml
进行声明
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<!-- ... -->
<application>
<!--
1. name 为 CustomProvider 的全途径,或许相关于资源文件的途径
2. authorities 加上 ${applicationId} 能够有用避免多个运用依靠该组件重复,导致不能装置问题
3. exported = false,让外部不能运用,朴实只是为了当时组件的初始化
-->
<provider
android:name="CustomProvider的途径"
android:authorities="${applicationId}.custom-startup"
android:exported="false" />
<!-- ... -->
</application>
</manifest>
优缺陷
- 长处:在运用发动的时候,体系会调用
ContentProvider#onCreate
进行初始化,则避免组件运用方在主module
中Application#onCreate
初始化,关于组件运用方来说是无感知的; - 缺陷:假如组件间初始化是有依靠性,则多个
Provider
在清单文件中的次序是有要求的,但这个是非常困难进行调整的,而且很简单错;同时Provider
的实例化本钱昂扬,在不必要的情况下可能会拖慢发动序列
ContentProvider#onCreate
初始化途径(基于android33)
- ActivityThread#main(
zygote
新建进程,执行ActivityThread
的main
办法,执行主Looper
循环) - ActivityThread#attach(
ActivityThread
初始化) - ActivityManagerService#attachApplication(
Binder
调用,从运用 =>ActivityManagerService
) - ApplicationThread#bindApplication(
Binder
调用,从ActivityManagerService
=> 运用) - H#handleMessage(BIND_APPLICATION)(运用
H
进行分发) - ActivityThread#handleBindApplication(当时运用绑定
application
) - ActivityThread#installContentProviders(装置多个
Provider
) - ActivityThread#installProvider(装置单个
Provider
) - ContentProvider#attachInfo
- ContentProvider#onCreate
办法三:运用 Jetpack startup
组件库进行初始化
运用办法
- 在
module
模块的build.gradle
引证Jetpack startup
dependencies {
implementation "androidx.startup:startup-runtime:1.1.1"
}
- 承继
Initializer<*>
,重写onCreate
和dependencies
办法,
class CustomInitializer : Initializer<Custom> {
override fun create(context: Context): Custom {
// Custom 初始化
return Custom.getInstance(context)
}
override fun dependencies(): List<Class<out Initializer<*>>> {
// 声明当时依靠的类库
return emptyList()
}
}
- 在模块
AndroidManifest.xml
中声明
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<!-- ... -->
<application>
<!--
1. name 为固定 androidx.startup.InitializationProvider,则知道是用这个来进行初始化的
2. authorities = "${applicationId}.androidx-startup" 用于避免多个运用导致的重复
3. exported 仅供本身运用,不对外露出
4. tools:node = "merge" 表明合并相同的 InitializationProvider,在这儿代表合并其他组件的 meta-data
-->
<provider
android:name="androidx.startup.InitializationProvider"
android:authorities="${applicationId}.androidx-startup"
android:exported="false"
tools:node="merge">
<!--
1. name 为 CustomInitializer 的全途径,或许相关于资源文件的途径
2. value 为固定的 androidx.startup,用于提取 CustomInitializer 的途径
-->
<meta-data android:name="CustomInitializer的途径"
android:value="androidx.startup" />
</provider>
<!-- ... -->
</application>
</manifest>
优缺陷
- 长处:解决办法二中的2个问题;在整体运用中,只存在一个
Provider
,而且Initializer#dependencies
中声明该组件所依靠组件,在初始该组件的时候会先初始化该组件所依靠组件 - 缺陷:从
Initializer#dependencies
办法参数可知,需要所依靠组件实现Initializer
才能够,需要改动本来的组件;但假如后续的组件都按照此来声明,关于运用方来说,会更加简单
源码解析
- 从
android:name
可知InitializationProvider
进口
// androidx.startup.InitializationProvider
public class InitializationProvider extends ContentProvider {
@Override
public final boolean onCreate() {
Context context = getContext();
if (context != null) {
Context applicationContext = context.getApplicationContext();
if (applicationContext != null) {
// 调用 AppInitializer 的 discoverAndInitialize
AppInitializer.getInstance(context).discoverAndInitialize();
} else {
StartupLogger.w("Deferring initialization because `applicationContext` is null.");
}
} else {
throw new StartupException("Context cannot be null");
}
return true;
}
// ...
}
AppInitializer#discoverAndInitialize
public final class AppInitializer {
private static volatile AppInitializer sInstance;
private static final Object sLock = new Object();
final Map<Class<?>, Object> mInitialized;
final Set<Class<? extends Initializer<?>>> mDiscovered;
final Context mContext;
@NonNull
public static AppInitializer getInstance(@NonNull Context context) {
// 双重校验获取 AppInitializer
if (sInstance == null) {
synchronized (sLock) {
if (sInstance == null) {
sInstance = new AppInitializer(context);
}
}
}
return sInstance;
}
AppInitializer(@NonNull Context context) {
mContext = context.getApplicationContext(); // application context
mDiscovered = new HashSet<>(); // 已发现的Initializer
mInitialized = new HashMap<>(); // 已初始化的内容
}
void discoverAndInitialize() {
try {
// step1: 创立包括 InitializationProvider 类信息的 ComponentName
ComponentName provider = new ComponentName(mContext.getPackageName(),
InitializationProvider.class.getName());
// step2: 获取 InitializationProvider 对应的 META_DATA 信息
ProviderInfo providerInfo = mContext.getPackageManager()
.getProviderInfo(provider, GET_META_DATA);
Bundle metadata = providerInfo.metaData;
// step3: 解析metadata
discoverAndInitialize(metadata);
} catch (PackageManager.NameNotFoundException exception) {
throw new StartupException(exception);
}
}
void discoverAndInitialize(@Nullable Bundle metadata) {
// step4: 获取 startup 字符串
String startup = mContext.getString(R.string.androidx_startup);
try {
if (metadata != null) {
// step5: initializing 记载正在初始化的类,主要用于避免循环引证
Set<Class<?>> initializing = new HashSet<>();
Set<String> keys = metadata.keySet();
for (String key : keys) {
String value = metadata.getString(key, null);
// step6: 这儿限定了 android:value 只能为 startup 的值
if (startup.equals(value)) {
// step7: 反射获取此类,并查看是否是 Initializer 的子类
Class<?> clazz = Class.forName(key);
if (Initializer.class.isAssignableFrom(clazz)) {
Class<? extends Initializer<?>> component =
(Class<? extends Initializer<?>>) clazz;
// step8: 记载当时类进入发现调集中
mDiscovered.add(component);
}
}
}
// step9: 遍历当时发现的类,开端初始化
for (Class<? extends Initializer<?>> component : mDiscovered) {
// Tips: initializing 记载正在初始化的类,这儿为空调集
doInitialize(component, initializing);
}
}
} catch (ClassNotFoundException exception) {
throw new StartupException(exception);
}
}
@NonNull
@SuppressWarnings({"unchecked", "TypeParameterUnusedInFormals"})
private <T> T doInitialize(
@NonNull Class<? extends Initializer<?>> component,
@NonNull Set<Class<?>> initializing) {
try {
// step10: 假如 initializing 包括 component,则证明呈现循环依靠
if (initializing.contains(component)) {
String message = String.format(
"Cannot initialize %s. Cycle detected.", component.getName()
);
throw new IllegalStateException(message);
}
Object result;
// step11: 查看此类是否已初始化,已初始化这直接返回,反之进行初始化
if (!mInitialized.containsKey(component)) {
initializing.add(component);
try {
// step12: 运用反射调用结构参数;由这可知这儿需要一个默许的空参的结构函数
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) {
// step13: 假如当时依靠组件未进行初始化,则进行初始化
if (!mInitialized.containsKey(clazz)) {
doInitialize(clazz, initializing);
}
}
}
// step14: 调用 Initializer#create 创立组件
result = initializer.create(mContext);
// step15: 当时组件初始化完结,从正在初始化调集移除和加入已初始化调集中
initializing.remove(component);
mInitialized.put(component, result);
} catch (Throwable throwable) {
throw new StartupException(throwable);
}
} else {
result = mInitialized.get(component);
}
return (T) result;
}
}
// ======================= 剩余办法 =======================
@NonNull
@SuppressWarnings("unused")
public <T> T initializeComponent(@NonNull Class<? extends Initializer<T>> component) {
return doInitialize(component);
}
public boolean isEagerlyInitialized(@NonNull Class<? extends Initializer<?>> component) {
return mDiscovered.contains(component);
}
@NonNull
@SuppressWarnings({"unchecked", "TypeParameterUnusedInFormals"})
<T> T doInitialize(@NonNull Class<? extends Initializer<?>> component) {
Object result;
synchronized (sLock) {
result = mInitialized.get(component);
if (result == null) {
result = doInitialize(component, new HashSet<Class<?>>());
}
}
return (T) result;
}
}
Tips
从上述的源码解析可知,整个进程分为2部分
- 提取当时
Provider
的meta-data
数据,从meta-data
上能够获取对应Initializer
的类信息 - 根据提取到
Initializer
的类信息,进行反射调用结构函数和调用onCreate
办法;
因而能够不运用第一步进行初始化,选择合适机遇进行初始化,也就官网说的推迟初始化, 此时调用上述
AppInitializer#initializeComponent
进行初始化
默许行为是从 Provider
清单文件声明 meta-data
提取类信息,因而当不需要某个初始化的时候,能够屏蔽对应 meta-data
的类信息;或许运用 aapt2
所带的 tools:node="remove"
进行移除
<provider
android:name="androidx.startup.InitializationProvider"
android:authorities="${applicationId}.androidx-startup"
android:exported="false"
tools:node="merge">
<!-- tools:node="remove" 在构建的时候,不会打进去 -->
<meta-data android:name="com.example.ExampleLoggerInitializer"
tools:node="remove" />
</provider>
同时 tools:node="remove"
也适用于 provider
结点,使整个 provider
结点移除
<provider
android:name="androidx.startup.InitializationProvider"
android:authorities="${applicationId}.androidx-startup"
tools:node="remove" />