我的Github:https://github.com/BzCoder
本文基于MVPArms进行分析:https://github.com/JessYanCoding/MVPArms
欢迎各位留言讨论
前段时间赶项目,耽误了一些时间,没有及时更新文章。
在组件化开发中,每个模块都可能会拥有独有的配置,在打包时,又有全局统一管理的配置。我们就要对这里最终进行整合。我们分为四个点来讨论。
- 收集配置
- 配置Applicaition
- 配置Activity
- 配置Fragment
跨模块收集配置
因为组件化改造后,配置都分散在各个模块中,我们需要借助手段将它们再集中起来,此时我们可以借用Manifest,因为在整体运行阶段,系统会将Manifest统一合并形成一份Manifest。利用这个特性,我们可以通过meta-data的方式将散落在各个模块集中到一起。下方代码可以帮助收集配置,以下代码分了两个步骤,首先将Manifest中meta-data的value为ConfigModule取出,然后通过它的Key去反射实例化ConfigModule配置文件,最后返回List
public final class ManifestParser {
private static final String MODULE_VALUE = "ConfigModule";
private final Context context;
public ManifestParser(Context context) {
this.context = context;
}
public List parse() {
List modules = new ArrayList();
try {
ApplicationInfo appInfo = context.getPackageManager().getApplicationInfo(
context.getPackageName(), PackageManager.GET_META_DATA);
if (appInfo.metaData != null) {
for (String key : appInfo.metaData.keySet()) {
if (MODULE_VALUE.equals(appInfo.metaData.get(key))) {
modules.add(parseModule(key));
}
}
}
} catch (PackageManager.NameNotFoundException e) {
throw new RuntimeException("Unable to find metadata to parse ConfigModule", e);
}
return modules;
}
private static ConfigModule parseModule(String className) {
Class> clazz;
try {
clazz = Class.forName(className);
} catch (ClassNotFoundException e) {
throw new IllegalArgumentException("Unable to find ConfigModule implementation", e);
}
Object module;
try {
module = clazz.newInstance();
} catch (InstantiationException e) {
throw new RuntimeException("Unable to instantiate ConfigModule implementation for " + clazz, e);
} catch (IllegalAccessException e) {
throw new RuntimeException("Unable to instantiate ConfigModule implementation for " + clazz, e);
}
if (!(module instanceof ConfigModule)) {
throw new RuntimeException("Expected instanceof ConfigModule, but found: " + module);
}
return (ConfigModule) module;
}
}
在ConfigModule接口中包含了四个方法,参数为context , List<>
,这方便在各个模块中注入配置。
public interface ConfigModule {
void injectAppLifecycle(@NonNull Context context, @NonNull List lifecycles);
void injectActivityLifecycle(@NonNull Context context, @NonNull List lifecycles);
void injectFragmentLifecycle(@NonNull Context context, @NonNull List lifecycles);
}
Application
因为一个App只有一个Application,但是由于我们是组件化开发,我们并不能在每个模块当中直接对Application进行操作,但是上面的代码已经帮我们解决掉了最关键的收集配置问题,所以接下来我们使用代理模式就可以解决各个模块Application的拼装问题。我们模仿LifeCycle的写法。
public interface AppLifecycles {
void attachBaseContext(@NonNull Context base);
void onCreate(@NonNull Application application);
void onTerminate(@NonNull Application application);
void onTrimMemory(@NonNull Application application);
void onLowMemory(@NonNull Application application,int level);
}
我们新建类AppDelegate来实现AppLifecycles
在Application中我们只需要在相应的生命周期方法中调用即可。其中AppLifecycles 为我们从上文中List
取得。
for (AppLifecycles lifecycle : mAppLifecycles) {
lifecycle.attachBaseContext(base);
}
配置Activity
在Api14后,Application中加入了ActivityLifecycleCallbacks,这里我们要区分它和LifeCycle的不同,ActivityLifecycleCallbacks是在Applicaiton中对于所有Activity统一管理,更像是BaseActivity的概念,LifeCycle是Acitivity内部组件的生命周期监听。ActivityLifecycleCallbacks我们经常用来:嵌入第三方SDK在Activity中的启动,控制某个Activity被初始化的数量,如各种详情页详情页,判断应用是否在前台状态等。所以Acitivity的管理,我们可以直接拿来即用。我们只要把List
取得的List
通过Application.registerActivityLifecycleCallbacks(lifecycle)
注册到基Application即可。
配置Fragment
Fragment依附于Activity,所以对于Fragment的配置我们需要在Activity的onCreate中进行。在FragmentActivity中,系统给我们提供了registerFragmentLifecycleCallbacks(@NonNull FragmentManager.FragmentLifecycleCallbacks var1, boolean var2);
方法,其中布尔值True代表递归注册,就是当Fragment嵌套Fragment的情况。于是我们在配置Fragment时,只需要在基类中的ActivityLifecycleCallback的onActivityCreated中调用registerFragmentLifecycleCallbacks即可,当然会有同学问此处的List
以上就完成了在组件化开发中对于不同模块的Applicaition,Activity,Fragment配置的统一管理。