在组件化开发的过程中,在不增加模块间耦合的情况下,如果某些功能模块需要进行初始化,如何进行操作呢?这里先说一下常规的配置思路,后面会在这种方式的基础上做进一步的优化。
(1)在base模块中定义抽象类,类中涵盖了Application中的几个方法。
public abstract class BaseAppLogic {
protected Application mApplication;
public BaseAppLogic(){
}
public void setApplication(Application application){
this.mApplication = application;
}
public void onCreate(){}
public void onTerminate(){}
public void onLowMemory(){}
public void onTrimMemory(int level){}
public void onConfigurationChanged(Configuration newConfig){}
}
(2)在功能模块中创建一个”假的”Application继承该BaseAppLogic
public class TestApplication extends BaseAppLogic {
private static final String TAG = "TestApplication";
@Override
public void onCreate() {
super.onCreate();
Log.e(TAG,"test for application");
}
@Override
public void onLowMemory() {
super.onLowMemory();
}
@Override
public void onTrimMemory(int level) {
super.onTrimMemory(level);
}
@Override
public void onTerminate() {
super.onTerminate();
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
}
}
(3)将主模块中的Application与功能模块的”Application”进行绑定。
public class MainApplication extends Application {
private String[] appClazz = new String[]{"com.px.xxx.TestApplication"};
private ArrayList<BaseAppLogic> applicationList = new ArrayList<>();
@Override
public void onCreate() {
super.onCreate();
initAppLogic();
}
private void initAppLogic(){
for(String className : appClazz){
try {
Class<?> clazz = Class.forName(className);
try {
BaseAppLogic appLogic = (BaseAppLogic) clazz.newInstance();
appLogic.onCreate();
applicationList.add(appLogic);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
@Override
public void onTerminate() {
super.onTerminate();
for(BaseAppLogic appLogic:applicationList){
appLogic.onTerminate();
}
}
}
至此,为了降低耦合,使用反射完成了组件化的Application的配置。(什么?你说使用反射影响性能?下一篇我们来探讨反射对性能的影响究竟有多大)。对于项目中功能组件较少,或者开发团队成员较少的情况,使用以上的方式就足够了。
我们可以看到在(3)中,我们需要显示的在主模块中注册功能模块”Application”的类名,这样虽然我们实现了代码上的低耦合,却没有实现在开发过程中人员模块操作界限的分离。在实际的开发过程中,开发人员各自负责自己的模块,甚至有可能没有主模块的修改权限。为此我将上述方案推进了一步,使用编译时注解自动实现模块中”Application”信息的收集。
(1)定义注解。该注解用来标识上述功能模块中假的”Application”
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.CLASS)
public @interface AppLogic {
//为true时在Application的onCreate方法中最后执行
boolean delay() default false;
//优先级,值越大越先执行
int priority() default 0;
}
(2)使用poet实现对该运行时注解的解释器,目的是将所有被注解的类的信息收集起来。
@AutoService(Processor.class)
@SupportedAnnotationTypes({"com.px.annotation.AppLogic"})
@SupportedSourceVersion(SourceVersion.RELEASE_7)
public class AppLogicProcessor extends AbstractProcessor {
private Filer filer;
private ArrayList<AppLogicInfo> mData = new ArrayList<>();
@Override
public synchronized void init(ProcessingEnvironment processingEnvironment) {
super.init(processingEnvironment);
filer = processingEnv.getFiler();
}
@Override
public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
collectInfo(roundEnvironment);
writeToFile();
return true;
}
//收集所有被注解的类的信息
private void collectInfo(RoundEnvironment roundEnvironment){
Set<? extends Element> elements = roundEnvironment.getElementsAnnotatedWith(AppLogic.class);
for(Element element : elements){
AppLogicInfo appLogicInfo = new AppLogicInfo();
boolean delay = element.getAnnotation(AppLogic.class).delay();
int priority = element.getAnnotation(AppLogic.class).priority();
TypeElement typeElement = (TypeElement)element;
String classFullName = typeElement.getQualifiedName().toString();
appLogicInfo.setClassName(classFullName);
appLogicInfo.setDelay(delay);
appLogicInfo.setPriority(priority);
mData.add(appLogicInfo);
}
}
//将被注解的类的信息,写到一个类""Test$$AppLogic.java""中
public void writeToFile() {
try {
String packageFullName = "com.px.applogicdem";
ClassName ArrayList = ClassName.get("java.util","ArrayList");
ClassName appLogicInfo = ClassName.get("com.px.api","AppLogicInfo");
TypeName arrayListType = ParameterizedTypeName.get(ArrayList, appLogicInfo);
FieldSpec arrayList = FieldSpec.builder(arrayListType,"testArrayList")
.addModifiers(Modifier.PUBLIC)
.initializer("new $T()",arrayListType)
.build();
MethodSpec.Builder methodSpec2 = MethodSpec.constructorBuilder()
.addModifiers(Modifier.PUBLIC);
for(int i= 0;i<mData.size();i++){
String temp = "temp"+i;
methodSpec2.addStatement("$T "+temp+" = new $T()",appLogicInfo ,appLogicInfo)
.addStatement(temp+".setClassName($S)",mData.get(i).getClassName())
.addStatement(temp+".setDelay("+mData.get(i).isDelay()+")")
.addStatement(temp+".setPriority("+mData.get(i).getPriority()+")")
.addStatement("testArrayList.add("+temp+")");
}
// 构建Class
TypeSpec typeSpec = TypeSpec.classBuilder("Test" + "$$AppLogic")
.addModifiers(Modifier.PUBLIC)
.addMethod(methodSpec2.build())
.addField(arrayList)
.build();
JavaFile javaFile = JavaFile.builder(packageFullName, typeSpec)
.build();
// 生成class文件
javaFile.writeTo(filer);
} catch (IOException e) {
e.printStackTrace();
}
}
}
(3)为功能模块中的Application添加注解
@AppLogic
public class TestApplication extends BaseAppLogic {
private static final String TAG = "TestApplication";
@Override
public void onCreate() {
super.onCreate();
Log.e(TAG,"test for application");
}
@Override
public void onLowMemory() {
super.onLowMemory();
}
@Override
public void onTrimMemory(int level) {
super.onTrimMemory(level);
}
@Override
public void onTerminate() {
super.onTerminate();
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
}
}
(4)编译一下代码,检查下注解解释器是否为我们自动生成了类,poet生成的代码如下。
public class Test$$AppLogic {
public ArrayList<AppLogicInfo> testArrayList = new ArrayList<AppLogicInfo>();
public Test$$AppLogic() {
AppLogicInfo temp0 = new AppLogicInfo();
temp0.setClassName("com.px.testlib.TestApplication");
temp0.setDelay(false);
temp0.setPriority(0);
testArrayList.add(temp0);
}
}
(5)有了第四步的自动生成的代码,我们就可以通过一个工具类将主模块中的Application与功能模块中的”Application”进行绑定了。
public class AppLogicInject {
private static ArrayList<AppLogicInfo> appLogicInfos;
private static Application mApplication;
private static ArrayList<BaseAppLogic> appLogicList = new ArrayList<>();
public static void inject(Application application) {
mApplication = application;
String className = "com.px.applogicdem.Test$$AppLogic";
try {
Class clasz = Class.forName(className);
Object object = clasz.newInstance();
Field field = object.getClass().getField("testArrayList");
appLogicInfos = (ArrayList<AppLogicInfo>) field.get(object);
Collections.sort(appLogicInfos, new AppLogicInfo());
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
}
public static void onCreate() {
if(appLogicInfos == null){
return;
}
for (AppLogicInfo appLogicInfo : appLogicInfos) {
if (appLogicInfo.isDelay()) {
continue;
}
createAppLogic(appLogicInfo);
}
}
public static void onCreateDelay() {
if(appLogicInfos == null){
return;
}
for (AppLogicInfo appLogicInfo : appLogicInfos) {
if (appLogicInfo.isDelay()) {
createAppLogic(appLogicInfo);
}
}
}
private static void createAppLogic(AppLogicInfo appLogicInfo) {
try {
Class<?> clazz = Class.forName(appLogicInfo.getClassName());
BaseAppLogic appLogic = (BaseAppLogic) clazz.newInstance();
appLogic.setApplication(mApplication);
appLogic.onCreate();
appLogicList.add(appLogic);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
}
}
public static void onTerminate() {
for (BaseAppLogic appLogic : appLogicList) {
appLogic.onTerminate();
}
}
public static void onLowMemory() {
for (BaseAppLogic appLogic : appLogicList) {
appLogic.onLowMemory();
}
}
public static void onTrimMemory(int level) {
for (BaseAppLogic appLogic : appLogicList) {
appLogic.onTrimMemory(level);
}
}
public static void onConfigurationChanged(Configuration newConfig) {
for (BaseAppLogic appLogic : appLogicList) {
appLogic.onConfigurationChanged(newConfig);
}
}
}
(6)Application中的代码如下
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
AppLogicInject.inject(this);
AppLogicInject.onCreate();
//其他的初始化操作
AppLogicInject.onCreateDelay();
}
@Override
public void onTerminate() {
super.onTerminate();
AppLogicInject.onTerminate();
}
@Override
public void onLowMemory() {
super.onLowMemory();
AppLogicInject.onLowMemory();
}
@Override
public void onTrimMemory(int level) {
super.onTrimMemory(level);
AppLogicInject.onTrimMemory(level);
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
AppLogicInject.onConfigurationChanged(newConfig);
}
}