一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第8天,点击查看活动详情。
问题
随着项目代码量越来越大,每次编译的时候都会等上很长时间,极大降低了开发效率,而且随着功能的复杂度上升,代码耦合程度也越来越高,为了解决这些问题,很多项目都引入了组件化,将不同业务模块单独抽离成组件,单独编译测试,不同业务模块之间解耦,但是有的组件需要在Application
中初始化,如果我们为每个组件都提供一个Application
,虽然能单独编译运行,但是在最后所有组件一起打包的时候会遇到Manifest merger failed
的问题,那么如何解决这个问题呢,我们可以参考谷歌App Startup
库的做法。
实现
1. 定义ApplicationDelegate
首先,我们定义一个ApplicationDelegate
接口,并定义attachBaseContext()
和onCreate()
方法,用来代理真正Application
中对应的方法。
public interface ApplicationDelegate {
void attachBaseContext(Application application,Context context);
void onCreate(Application application);
}
2. 使用ApplicationDelegate
在需要使用Application的组件中实现ApplicationDelegate,例如common模块初始化ARouter
public class CommonApplicationDelegate implements ApplicationDelegate {
@Override
public void attachBaseContext(Application application, Context context) {
}
@Override
public void onCreate(Application application) {
if(BuildConfig.DEBUG){
ARouter.openDebug();
ARouter.openLog();
}
ARouter.init(application);
}
}
3. 代理Application
在base库中创建真正的BaseApplication
并继承自Application
,随后将Application
的attachBaseContext()
和onCreate()
方法交给ApplicationDelegate
处理,由于我们项目有多个组件,所以使用List将ApplicationDelegate
保存。
public class BaseApplication extends Application {
List<ApplicationDelegate> delegates;
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
delegates = findApplicationDelegate(base);
if (delegates != null) {
for (ApplicationDelegate delegate : delegates) {
delegate.attachBaseContext(this,base);
}
}
}
@Override
public void onCreate() {
super.onCreate();
if (delegates != null) {
for (ApplicationDelegate delegate : delegates) {
delegate.onCreate(this);
}
}
}
}
4. 注册ApplicationDelegate
在上一步处理的时候我们发现需要先找到ApplicationDelegate
。也就是定义findApplicationDelegate()
方法,不过在查找之前,需要先对ApplicationDelegate
进行注册,开头的时候说了我们参考App Startup
的做法,它是在<provider>
节点中添加meta-data
,所以我们可以仿照在application
节点中添加meta-data
,如下:
//首页组件
<application>
<meta-data android:value="ApplicationDelegate" android:name=".HomeApplicationDelegate"/>
</application>
//登录组件
<application>
<meta-data android:value="ApplicationDelegate" android:name=".LoginApplicationDelegate"/>
</application>
5. 查找ApplicationDelegate
首先我们通过PackageManager
获取到ApplicationInfo
,然后获取metaData
,找到我们需要的ApplicationDelegate
private static final String MODULE_META_KEY = "ApplicationDelegate";
public List<ApplicationDelegate> findApplicationDelegate(Context context) {
List<ApplicationDelegate> delegates = new ArrayList<>();
try {
PackageManager pm = context.getPackageManager();
String packageName = context.getPackageName();
ApplicationInfo info = pm.getApplicationInfo(packageName, GET_META_DATA);
if (info != null && info.metaData != null) {
for (String key : info.metaData.keySet()) {
Object value = info.metaData.get(key);
if (MODULE_META_KEY.equals(value)) {
ApplicationDelegate delegate = initApplicationDelegate(key);
if (delegate != null) {
delegates.add(delegate);
}
}
}
}
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
return delegates;
}
6. 实例化ApplicationDelegate
获取到ApplicationDelegate
之后,只需要通过反射创建其对象就可以了
private ApplicationDelegate initApplicationDelegate(String className) {
Class<?> clazz;
Object instance = null;
try {
clazz = Class.forName(className);
} catch (ClassNotFoundException e) {
throw new IllegalArgumentException("找不到" + className, e);
}
try {
instance = clazz.newInstance();
} catch (Exception e) {
throw new RuntimeException("不能获取 " + className + " 的实例", e);
}
if (!(instance instanceof ApplicationDelegate)) {
throw new RuntimeException("不能获取 " + ApplicationDelegate.class.getName() + " 的实例 " + instance);
}
return (ApplicationDelegate) instance;
}
最后别忘了将BaseApplication注册到base模块AndroidManifest.xml
中