Android组件化-动态配置Application实践

    在组件化开发的过程中,在不增加模块间耦合的情况下,如果某些功能模块需要进行初始化,如何进行操作呢?这里先说一下常规的配置思路,后面会在这种方式的基础上做进一步的优化。

(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);
    }
}

Demo下载地址

    原文作者:xu_pan
    原文地址: https://www.jianshu.com/p/e5f507efef6c
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞