组件化开发Aroute原理简析

对组件化开发的基本认识中,各个模块之间的通讯方式明显不能满足项目需求,此时就需要一个通讯框架实现模块之间的通讯。框架的意义就在于实现解耦的前提下,能够让各组件之间完成通讯。所以简单学习了一个Aroute框架权当记录,错误的地方还请指正

本demo设置了主程序和登录模块,一些基本的配置,例如library开关,manifest设置等本文就不再描述,直接简述Aroute的流程

创建ArouteLibrary依赖库,让主程序和登录模块依赖此项目

public class Aroute {
//    存放key和对应activity的map
    private Map<String, Class<? extends Activity>> maps;
//    上下文对象
    private Context context;
//  初始化上下文,遍历整个apk中类,找到放入ActivityUtil类,执行往map中放入activity的方法
    public void init(Context context) {
        this.context = context;
//        获取com.syw.util包下所有的类
        List<String> classNames = getClassName("com.syw.util");
        for (String className : classNames) {
            try {
//                通过反射获取类
                Class<?> aClass = Class.forName(className);
//                判断该类是否是IRouter的子类
                if (IRouter.class.isAssignableFrom(aClass)) {
//                  创建类对象
//					IRouter接口包含putActivity方法,由注解处理器生成的代码重写,具体实现添加k-v到map中。规范代码,方便统一调用
                    IRouter iRouter = (IRouter) aClass.newInstance();
//                    执行类对象中putActivity方法,将所有有注解的类加入到map中
                    iRouter.putActivity();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    public Aroute() {
//        在Aroute初始化的时候,创建map
        maps = new HashMap<>();
    }

    public static Aroute instance = new Aroute();

    public static Aroute getInstance() {
        return instance;
    }

    /**
     * 将有注解的类存入map
     * @param key 注解内容
     * @param clazz 该注解对应的类
     */
    public void addActivity(String key, Class<? extends Activity> clazz) {
        if (key != null && clazz != null && !maps.containsKey(key)) {
            maps.put(key, clazz);
        }
    }

    /**
     * 根据用户传入的key,找到类,完成跳转
     * @param key
     * @param bundle
     */
    public void jumpActivity(String key, Bundle bundle) {
        Class<? extends Activity> activityClass = maps.get(key);
        if (activityClass != null) {
            Intent intent = new Intent(context, activityClass);
            if (bundle != null) {
                intent.putExtras(bundle);
            }
            context.startActivity(intent);
        } 
    }

    /**
     * 获取所有指定包名下的类
     * @param packageName
     * @return
     */
    private List<String> getClassName(String packageName) {
        List<String> classList = new ArrayList<>();
        String path = null;
        try {
//            获取apk的完整路径
            path = context.getPackageManager().getApplicationInfo(context.getPackageName(), 0).sourceDir;
//            根据apk路径获取编译后的dex文件目录
            DexFile dexFile = new DexFile(path);
//            获取编译后dex文件中的所有class
            Enumeration<String> entries = dexFile.entries();
//            遍历当前应用所有文件class
            while (entries.hasMoreElements()) {
                String name = entries.nextElement();
                if (name.contains(packageName)) {
//                    如果符合就添加到集合
                    classList.add(name);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return classList;
    }
}

编写注解和注解处理器

Aroute用到的是apt技术,也就是编译时技术。在编译期执行,包括注解和注解处理器

注解

我们可以自定义注解,对类/方法等进行标记
新建一个java依赖库,创建一个类对象

@Target(ElementType.TYPE)//TYPE表示该注解放到类上边,@Override放到方法上,@Target(ElementType.METHOD)
@Retention(RetentionPolicy.CLASS)//表示生命周期存在于编译期,代码有源码期--编译期--运行期,Override是源码期,所以编译后的代码,没有@Override
public @interface BindPath {
//    用于获取注解中的内容
    String value();
}
注解处理器

本demo中注解处理器的作用是:在编译期在指定目录下,在各个模块生成我们想要的java代码。
新建一个java依赖库依赖注解模块,创建一个注解处理器类

//向javac注册我们这个自定义的注解处理器,这样,在javac编译时,才会调用到我们这个自定义的注解处理器方法。
//AutoService这里主要是用来生成META-INF/services/javax.annotation.processing.Processor文件的。
//使用AutoService需要添加以下依赖
// as 3.4以上版本
//    annotationProcessor 'com.google.auto.service:auto-service:1.0-rc4'
//    compileOnly 'com.google.auto.service:auto-service:1.0-rc3'
// as 3.4以下版本
//    implementation 'com.google.auto.service:auto-service:1.0-rc3'
@AutoService(Processor.class)
public class AnnotationCompiler extends AbstractProcessor {
    Filer filer;

    @Override
    public synchronized void init(ProcessingEnvironment processingEnvironment) {
        super.init(processingEnvironment);
        filer = processingEnvironment.getFiler();
    }

    @Override
    // 获取java版本
    public SourceVersion getSupportedSourceVersion() {
        return processingEnv.getSourceVersion();
    }

    @Override
    //设置该处理器能处理的节点,必须是注解的全类名
    public Set<String> getSupportedAnnotationTypes() {
        Set<String> types = new HashSet<>();
        types.add(BindPath.class.getCanonicalName());
        return types;
    }

    @Override
    public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
//        查看该项目下的BindPath节点集合
        Set<? extends Element> elementsAnnotateWith = roundEnvironment.getElementsAnnotatedWith(BindPath.class);
        Map<String, String> map = new HashMap<>();
//        遍历节点
        for (Element element : elementsAnnotateWith) {
            TypeElement typeElement = (TypeElement) element;
//            从节点获取注解
            BindPath annotation = typeElement.getAnnotation(BindPath.class);
//            获取注解内容
            String key = annotation.value();
//            获取节点全类名
            Name activityName = typeElement.getQualifiedName();
//            将key-value存入map
            map.put(key, activityName + ".class");
        }
        if (map.size()>0){
            Writer writer=null;
            String activityName="ActivityUtil"+System.currentTimeMillis();
            try {
//                创建java文件
                JavaFileObject sourceFile = filer.createSourceFile("com.syw.util." + activityName);
                writer=sourceFile.openWriter();
//                拼接stringbuffer
                StringBuffer stringBuffer=new StringBuffer();
                stringBuffer.append("package com.syw.util;\n");
                stringBuffer.append("import com.syw.aroutelibrary.Aroute;\n");
                stringBuffer.append("import com.syw.aroutelibrary.IRouter;\n");
                stringBuffer.append("public class "+activityName+" implements IRouter{\n"
                +"@Override\n"+
                        "public void putActivity(){\n");

                Iterator<String> iterator = map.keySet().iterator();
                while (iterator.hasNext()){
                    String key=iterator.next();
                    String className=map.get(key);
                    stringBuffer.append("Aroute.getInstance().addActivity(\""+key+"\","+className
                    +");\n");
                }
                stringBuffer.append("\n}\n}");
//                写入java文件
                writer.write(stringBuffer.toString());
            } catch (IOException e) {
                e.printStackTrace();
            }finally {
                if (writer!=null){
                    try {
                        writer.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
        return false;
    }
}

各个模块添加注解依赖

//    编译时模块
    implementation project(':annotation')
//    编译到这行代码时,
//    1.向javac注册我们这个自定义的注解处理器
//    2.生成META-INF/services/javax.annotation.processing.Processor文件
//    3.通过反射执行生成文件的方法
    annotationProcessor project(':annotation_compiler')

AutoService生成文件如下图所示
在这里插入图片描述
自定义注解处理器最终生成的代码如下图所示
在这里插入图片描述

所有生成的部分已经完成,现在需要执行生成的代码,将所有内容存到map中也就是执行Aroute的init()方法

我在主项目的mainactivity中执行了该方法,如下所示

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Aroute.getInstance().init(this);
    }

    public void tologin(View view) {
        Aroute.getInstance().jumpActivity("login/login",null);
    }
}

完成跳转

总结:1.创建一个JavaLibrary用于注解,自定义我们的注解
2.创建一个JavaLibiary用于注解处理器,功能是:遍历dex文件中的类,将包含我们制定注解的对象添加到map,然后写入指定路径的java文件
3.各个模块依赖注解和注解处理器,当编译到annotationProcessor时,向javac注册注解处理器,生成Processor文件,通过反射方法执行注解处理器生成代码的方法
4.通过Aroute.init()方法,获取所有的生成代码,然后执行,实现将所有方法添加到map。当需要跳转的时候,直接根据key获取到对应的activity,完成跳转
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值