一个重点:
在Application里,attachBaseContext()方法的执行顺序是在onCreate()之前的
组件化的目的是为了业务解耦,每个业务模块需要不同的功能,例如车辆详情模块需要第三方分享,城市定位模块需要百度地位等。有些特殊功能的初始化需要在 Application 中去做,但是这些功能并非全部业务组件都用到的东西,放到 主工程Application 不合适。
因此,我想这样操作:
模块共有的初始化,放入主工程Application 中。
模块自身的特殊功能初始化,放在自己的 Application。
想法很美好,但实现前需要先思考一个问题:
多 Module 项目开发的时候,app module 和 library module 的 都有不同的自定义 Application ,可以共存并且自动合并吗?
答案是 No。
为啥不行?
首先,自定义 Application 需要声明在 AndroidManifest.xml 中。其次,每个 Module 都有该清单文件,但是最终的 APK 文件只能包含一个。因此,在构建应用时,Gradle 构建会将所有清单文件合并到一个封装到 APK 的清单文件中。
合并的优先级是:
App Module > Library Module
如果值 A 合并值 B,就会产生冲突错误,错误信息中给出了解决建议,在高优先级的 App Module 中使用 tools:replace=“android:name”,但这样做是直接用值 A 替换了值 B,并非我们想要的结果。
所以我们知道:
APP打开的时候,只会初始化主工程的application(打开主工程AndroidManifest,点击Merged
Manifest,就可以看到,其他的Module的application都被覆盖了,只剩下主工程application)
所以,换个道路走,在初始化主工程application的时候,对其他module的application进行初始化。
了解一下我们平时用到的getApplicationContext()和getBaseContext():
Application本身是没有getApplicationContext()和getBaseContext()这两个方法的,这两个方法其实在Application的父类ContextWrapper中,其中context是在attachBaseContext(Context base)中赋值的,所以我们重写attachBaseContext的时候,一定要记得调一遍super.attachBaseContext(base)传入当前context。
了解清楚Application的生命周期,那我们初始化module的application就操作就可以做了
主工程的application:
public class MainApplication extends Application {
private ModuleApplication moduleApplication;//module的Application映射
@Override
public void onCreate() {
super.onCreate();
//....一些主工程的初始化操作
//同步Module的Application的onCreate
if (moduleApplication != null){
moduleApplication.onCreate();//用于执行module的一些自定义初始化操作
}
}
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
moduleApplication = getModuleApplicationInstance(this);
try {
//通过反射调用moduleApplication的attach方法
Method method = Application.class.getDeclaredMethod("attach", Context.class);
if (method != null) {
method.setAccessible(true);
method.invoke(moduleApplication, getBaseContext());
}
} catch (Exception e) {
e.printStackTrace();
}
}
//映射获取ModuleApplication
private ModuleApplication getModuleApplicationInstance(Context paramContext) {
try {
if (moduleApplication == null) {
ClassLoader classLoader = paramContext.getClassLoader();
if (classLoader != null) {
Class<?> mClass = classLoader.loadClass(ModuleApplication.class.getName());
if (mClass != null)
moduleApplication = (ModuleApplication) mClass.newInstance();
}
}
} catch (Exception e) {
e.printStackTrace();
}
return moduleApplication;
}
}
可以看到,实际上就是主工程的Application和module的Application共用一个base,最后我们想要的结果也实现了。
Module的application (不用在Module的AndroidManifest中注册)
public ModuleApplication extends Application{
private static ModuleApplication instance;
public void onCreate(){
super.onCreate();
//...一些自定义操作
instance = this;
}
public static getInstance(){
return instance;
}
}
这样,主工程和Module的Application都能启动并初始化了,并且根据打印的log,查看各自的运行进程【Process.myPid()】,可以看到他们运行在同一个进程里,即应用默认的唯一主进程