Design and implementation of component-based routing architecture (c)

table of Contents

  • Routing Architecture Design
  • APT and generate routes Path class files Group
  • APT generate dynamic routing parameter file

Routing Architecture Design

Here Insert Picture Description
Why do you need a group name issue

Sub-module is loaded, the use of this "lazy loading" mode, to reduce memory usage to the greatest extent

Second problem makefile what role

The resulting file recording management activity facilitates bytecode object

Here Insert Picture Description

Here Insert Picture Description

Here Insert Picture Description

Components of the project deployment

Here Insert Picture Description

1)配置arouter_api/build.gradle

a.定义ARouterLoadGroup、ARouterLoadPath接口

b.在build.gradle声明依赖
    implementation project(":arouter_annotation")

2)配置common/build.gradle

implementation project(":arouter_annotation")
api project(":arouter_api")

3) completion code generated analog class APT

    public class ARouter$$Group$$Order implements ARouterLoadGroup {
    
        @Override
        public HashMap<String, Class<? extends ARouterLoadPath>> loadGroup() {
            HashMap<String, Class<? extends ARouterLoadPath>> map = new HashMap<>();
            //初始化appGroup
            map.put("order", ARouter$$Path$$Order.class);
            return map;
        }
    }
    
    
    public class ARouter$$Path$$Order implements ARouterLoadPath {

        @Override
        public HashMap<String, RouterBean> loadPath() {
            HashMap<String, RouterBean> map = new HashMap<>();
    
            //加入/app/MainActivity
            map.put("/order/OrderMainActivity",
                    RouterBean.create(OrderMainActivity.class,
                            "/order/OrderMainActivity",
                            "order"));
    
            return map;
        }
    }

4) App sub-module, an analog jump codes

     public void jumpOrder(View v){

        //获取要跳转的ARouterLoadGroup对象
        ARouterLoadGroup group = new ARouter$$Group$$Order();
        HashMap<String, Class<? extends ARouterLoadPath>> groupMap = group.loadGroup();
        
        //获取ARouterLoadPath模块
        Class<? extends ARouterLoadPath> orderClazz = groupMap.get("order");
        try {
            ARouterLoadPath loadPath = orderClazz.newInstance();
            HashMap<String, RouterBean> pathMap = loadPath.loadPath();
            //根据路径获取RouterBean对象
            RouterBean routerBean = pathMap.get("/order/OrderMainActivity");
            if (routerBean != null) {
                startActivity(new Intent(this, routerBean.getClazz()));
            }
        } catch (Exception e) {
            e.printStackTrace();
        } 
    }

5) demonstration jump
test OK

APT and generate routes Path class files Group

We need to generate the following two documents
Here Insert Picture Description

Parameters need to pass the module

当前注解处理器处理的模块名称
生成代码的包名


// 在gradle文件中配置选项参数值(用于APT传参接收)
// 切记:必须写在defaultConfig节点下
javaCompileOptions {
    annotationProcessorOptions {
        arguments = [moduleName :project.getName(),packageNameForAPT:packageNameForAPT]
    }
}

Dynamically generating path and file group

/**
 * 编码此类1句话:细心再细心,出了问题debug真的不好调试
 */
// AutoService则是固定的写法,加个注解即可
// 通过auto-service中的@AutoService可以自动生成AutoService注解处理器,用来注册
// 用来生成 META-INF/services/javax.annotation.processing.Processor 文件
@AutoService(Processor.class)
// 允许/支持的注解类型,让注解处理器处理
@SupportedAnnotationTypes({Constants.AROUTER_ANNOTATION_TYPES})
// 指定JDK编译版本
@SupportedSourceVersion(SourceVersion.RELEASE_7)
// 注解处理器接收的参数
@SupportedOptions({Constants.MODULE_NAME, Constants.APT_PACKAGE})
public class ARouterProcessor extends AbstractProcessor {

    // 操作Element工具类 (类、函数、属性都是Element)
    private Elements elementUtils;

    // type(类信息)工具类,包含用于操作TypeMirror的工具方法
    private Types typeUtils;

    // Messager用来报告错误,警告和其他提示信息
    private Messager messager;

    // 文件生成器 类/资源,Filter用来创建新的类文件,class文件以及辅助文件
    private Filer filer;

    // 子模块名,如:app/order/personal。需要拼接类名时用到(必传)ARouter$$Group$$order
    private String moduleName;

    // 包名,用于存放APT生成的类文件
    private String packageNameForAPT;

    // 临时map存储,用来存放路由组Group对应的详细Path类对象,生成路由路径类文件时遍历
    // key:组名"app", value:"app"组的路由路径"ARouter$$Path$$app.class"
    private Map<String, List<RouterBean>> tempPathMap = new HashMap<>();

    // 临时map存储,用来存放路由Group信息,生成路由组类文件时遍历
    // key:组名"app", value:类名"ARouter$$Path$$app.class"
    private Map<String, String> tempGroupMap = new HashMap<>();

    // 该方法主要用于一些初始化的操作,通过该方法的参数ProcessingEnvironment可以获取一些列有用的工具类
    @Override
    public synchronized void init(ProcessingEnvironment processingEnvironment) {
        super.init(processingEnvironment);
        elementUtils = processingEnvironment.getElementUtils();
        typeUtils = processingEnvironment.getTypeUtils();
        messager = processingEnvironment.getMessager();
        filer = processingEnvironment.getFiler();

        // 通过ProcessingEnvironment去获取对应的参数
        Map<String, String> options = processingEnvironment.getOptions();
        if (!EmptyUtils.isEmpty(options)) {
            moduleName = options.get(Constants.MODULE_NAME);
            packageNameForAPT = options.get(Constants.APT_PACKAGE);
            // 有坑:Diagnostic.Kind.ERROR,异常会自动结束,不像安卓中Log.e
            messager.printMessage(Diagnostic.Kind.NOTE, "moduleName >>> " + moduleName);
            messager.printMessage(Diagnostic.Kind.NOTE, "packageNameForAPT >>> " + packageNameForAPT);
        }

        // 必传参数判空(乱码问题:添加java控制台输出中文乱码)
        if (EmptyUtils.isEmpty(moduleName) || EmptyUtils.isEmpty(packageNameForAPT)) {
            throw new RuntimeException("注解处理器需要的参数moduleName或者packageName为空,请在对应build.gradle配置参数");
        }
    }

    /**
     * 相当于main函数,开始处理注解
     * 注解处理器的核心方法,处理具体的注解,生成Java文件
     *
     * @param set              使用了支持处理注解的节点集合
     * @param roundEnvironment 当前或是之前的运行环境,可以通过该对象查找的注解。
     * @return true 表示后续处理器不会再处理(已经处理完成)
     */
    @Override
    public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
        // 一旦有类之上使用@ARouter注解
        if (!EmptyUtils.isEmpty(set)) {
            // 获取所有被 @ARouter 注解的 元素集合
            Set<? extends Element> elements = roundEnvironment.getElementsAnnotatedWith(ARouter.class);

            if (!EmptyUtils.isEmpty(elements)) {
                // 解析元素
                try {
                    parseElements(elements);
                    return true;
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            // 坑:必须写返回值,表示处理@ARouter注解完成
            return true;
        }
        return false;
    }

    // 解析所有被 @ARouter 注解的 类元素集合
    private void parseElements(Set<? extends Element> elements) throws IOException {
        // 通过Element工具类,获取Activity、Callback类型
        TypeElement activityType = elementUtils.getTypeElement(Constants.ACTIVITY);

        // 显示类信息(获取被注解节点,类节点)这里也叫自描述 Mirror
        TypeMirror activityMirror = activityType.asType();

        // 遍历节点
        for (Element element : elements) {
            // 获取每个元素类信息,用于比较
            TypeMirror elementMirror = element.asType();
            messager.printMessage(Diagnostic.Kind.NOTE, "遍历元素信息:" + elementMirror.toString());

            // 获取每个类上的@ARouter注解中的注解值
            ARouter aRouter = element.getAnnotation(ARouter.class);

            // 路由详细信息,最终实体封装类
            RouterBean bean = new RouterBean.Builder()
                    .setGroup(aRouter.group())
                    .setPath(aRouter.path())
                    .setElement(element)
                    .build();

            // 高级判断:ARouter注解仅能用在类之上,并且是规定的Activity
            // 类型工具类方法isSubtype,相当于instance一样
            if (typeUtils.isSubtype(elementMirror, activityMirror)) {
                bean.setType(RouterBean.Type.ACTIVITY);
            } else {
                // 不匹配抛出异常,这里谨慎使用!考虑维护问题
                throw new RuntimeException("@ARouter注解目前仅限用于Activity类之上");
            }

            // 赋值临时map存储,用来存放路由组Group对应的详细Path类对象
            valueOfPathMap(bean);
        }

        // routerMap遍历后,用来生成类文件

        // 获取ARouterLoadGroup、ARouterLoadPath类型(生成类文件需要实现的接口)
        TypeElement groupLoadType = elementUtils.getTypeElement(Constants.AROUTE_GROUP); // 组接口
        TypeElement pathLoadType = elementUtils.getTypeElement(Constants.AROUTE_PATH); // 路径接口

        // 第一步:生成路由组Group对应详细Path类文件,如:ARouter$$Path$$app
        createPathFile(pathLoadType);

        // 第二步:生成路由组Group类文件(没有第一步,取不到类文件),如:ARouter$$Group$$app
        createGroupFile(groupLoadType, pathLoadType);
    }

    /**
     * 生成路由组Group对应详细Path,如:ARouter$$Path$$app
     *
     * @param pathLoadType ARouterLoadPath接口信息
     */
    private void createPathFile(TypeElement pathLoadType) throws IOException {
        // 判断是否有需要生成的类文件
        if (EmptyUtils.isEmpty(tempPathMap)) return;

        TypeName methodReturns = ParameterizedTypeName.get(
                ClassName.get(Map.class), // Map
                ClassName.get(String.class), // Map<String,
                ClassName.get(RouterBean.class) // Map<String, RouterBean>
        );

        // 遍历分组,每一个分组创建一个路径类文件,如:ARouter$$Path$$app
        for (Map.Entry<String, List<RouterBean>> entry : tempPathMap.entrySet()) {
            // 方法配置:public Map<String, RouterBean> loadPath() {
            MethodSpec.Builder methodBuidler = MethodSpec.methodBuilder(Constants.PATH_METHOD_NAME) // 方法名
                    .addAnnotation(Override.class) // 重写注解
                    .addModifiers(Modifier.PUBLIC) // public修饰符
                    .returns(methodReturns); // 方法返回值

            // 遍历之前:Map<String, RouterBean> pathMap = new HashMap<>();
            methodBuidler.addStatement("$T<$T, $T> $N = new $T<>()",
                    ClassName.get(Map.class),
                    ClassName.get(String.class),
                    ClassName.get(RouterBean.class),
                    Constants.PATH_PARAMETER_NAME,
                    HashMap.class);

            // 一个分组,如:ARouter$$Path$$app。有很多详细路径信息,如:/app/MainActivity、/app/OtherActivity
            List<RouterBean> pathList = entry.getValue();
            // 方法内容配置(遍历每个分组中每个路由详细路径)
            for (RouterBean bean : pathList) {
                // 类似String.format("hello %s net163 %d", "net", 163)通配符
                // pathMap.put("/app/MainActivity", RouterBean.create(
                //        RouterBean.Type.ACTIVITY, MainActivity.class, "/app/MainActivity", "app"));
                methodBuidler.addStatement(
                        "$N.put($S, $T.create($T.$L, $T.class, $S, $S))",
                        Constants.PATH_PARAMETER_NAME, // pathMap.put
                        bean.getPath(), // "/app/MainActivity"
                        ClassName.get(RouterBean.class), // RouterBean
                        ClassName.get(RouterBean.Type.class), // RouterBean.Type
                        bean.getType(), // 枚举类型:ACTIVITY
                        ClassName.get((TypeElement) bean.getElement()), // MainActivity.class
                        bean.getPath(), // 路径名
                        bean.getGroup() // 组名
                );
            }

            // 遍历之后:return pathMap;
            methodBuidler.addStatement("return $N", Constants.PATH_PARAMETER_NAME);

            // 最终生成的类文件名
            String finalClassName = Constants.PATH_FILE_NAME + entry.getKey();
            messager.printMessage(Diagnostic.Kind.NOTE, "APT生成路由Path类文件:" +
                    packageNameForAPT + "." + finalClassName);

            // 生成类文件:ARouter$$Path$$app
            JavaFile.builder(packageNameForAPT, // 包名
                    TypeSpec.classBuilder(finalClassName) // 类名
                            .addSuperinterface(ClassName.get(pathLoadType)) // 实现ARouterLoadPath接口
                            .addModifiers(Modifier.PUBLIC) // public修饰符
                            .addMethod(methodBuidler.build()) // 方法的构建(方法参数 + 方法体)
                            .build()) // 类构建完成
                    .build() // JavaFile构建完成
                    .writeTo(filer); // 文件生成器开始生成类文件

            // 非常重要一步!!!!!路径文件生成出来了,才能赋值路由组tempGroupMap
            tempGroupMap.put(entry.getKey(), finalClassName);
        }
    }

    /**
     *
     * public interface ARouterLoadGroup {
     *
     *     HashMap<String,Class<? extends ARouterLoadPath>> loadGroup();
     * }
     * 生成路由组Group文件,如:ARouter$$Group$$app
     *
     * @param groupLoadType ARouterLoadGroup接口信息
     * @param pathLoadType ARouterLoadPath接口信息
     */
    private void createGroupFile(TypeElement groupLoadType, TypeElement pathLoadType) throws IOException {
        // 判断是否有需要生成的类文件
        if (EmptyUtils.isEmpty(tempGroupMap) || EmptyUtils.isEmpty(tempPathMap)) return;

        TypeName methodReturns = ParameterizedTypeName.get(
                ClassName.get(Map.class), // Map
                ClassName.get(String.class), // Map<String,
                // 第二个参数:Class<? extends ARouterLoadPath>
                // 某某Class是否属于ARouterLoadPath接口的实现类
                ParameterizedTypeName.get(ClassName.get(Class.class),
                        WildcardTypeName.subtypeOf(ClassName.get(pathLoadType)))
        );

        // 方法配置:public Map<String, Class<? extends ARouterLoadPath>> loadGroup() {
        MethodSpec.Builder methodBuidler = MethodSpec.methodBuilder(Constants.GROUP_METHOD_NAME) // 方法名
                .addAnnotation(Override.class) // 重写注解
                .addModifiers(Modifier.PUBLIC) // public修饰符
                .returns(methodReturns); // 方法返回值

        // 遍历之前:Map<String, Class<? extends ARouterLoadPath>> groupMap = new HashMap<>();
        methodBuidler.addStatement("$T<$T, $T> $N = new $T<>()",
                ClassName.get(Map.class),
                ClassName.get(String.class),
                ParameterizedTypeName.get(ClassName.get(Class.class),
                        WildcardTypeName.subtypeOf(ClassName.get(pathLoadType))),
                Constants.GROUP_PARAMETER_NAME,
                HashMap.class);

        // 方法内容配置
        for (Map.Entry<String, String> entry : tempGroupMap.entrySet()) {
            // 类似String.format("hello %s net163 %d", "net", 163)通配符
            // groupMap.put("main", ARouter$$Path$$app.class);
            methodBuidler.addStatement("$N.put($S, $T.class)",
                    Constants.GROUP_PARAMETER_NAME, // groupMap.put
                    entry.getKey(),
                    // 类文件在指定包名下
                    ClassName.get(packageNameForAPT, entry.getValue()));
        }

        // 遍历之后:return groupMap;
        methodBuidler.addStatement("return $N", Constants.GROUP_PARAMETER_NAME);

        // 最终生成的类文件名
        String finalClassName = Constants.GROUP_FILE_NAME + moduleName;
        messager.printMessage(Diagnostic.Kind.NOTE, "APT生成路由组Group类文件:" +
                packageNameForAPT + "." + finalClassName);

        // 生成类文件:ARouter$$Group$$app
        JavaFile.builder(packageNameForAPT, // 包名
                TypeSpec.classBuilder(finalClassName) // 类名
                        .addSuperinterface(ClassName.get(groupLoadType)) // 实现ARouterLoadGroup接口
                        .addModifiers(Modifier.PUBLIC) // public修饰符
                        .addMethod(methodBuidler.build()) // 方法的构建(方法参数 + 方法体)
                        .build()) // 类构建完成
                .build() // JavaFile构建完成
                .writeTo(filer); // 文件生成器开始生成类文件
    }

    /**
     * 赋值临时map存储,用来存放路由组Group对应的详细Path类对象,生成路由路径类文件时遍历
     *
     * @param bean 路由详细信息,最终实体封装类
     */
    private void valueOfPathMap(RouterBean bean) {
        if (checkRouterPath(bean)) {
            messager.printMessage(Diagnostic.Kind.NOTE, "RouterBean >>> " + bean.toString());

            // 开始赋值Map
            List<RouterBean> routerBeans = tempPathMap.get(bean.getGroup());
            // 如果从Map中找不到key为:bean.getGroup()的数据,就新建List集合再添加进Map
            if (EmptyUtils.isEmpty(routerBeans)) {
                routerBeans = new ArrayList<>();
                routerBeans.add(bean);
                tempPathMap.put(bean.getGroup(), routerBeans);
            } else { // 找到了key,直接加入List集合
                routerBeans.add(bean);
            }

        } else {
            messager.printMessage(Diagnostic.Kind.ERROR, "@ARouter注解未按规范配置,如:/app/MainActivity");
        }
    }

    /**
     * 校验@ARouter注解的值,如果group未填写就从必填项path中截取数据
     *
     * @param bean 路由详细信息,最终实体封装类
     */
    private boolean checkRouterPath(RouterBean bean) {
        String group = bean.getGroup();
        String path = bean.getPath();

        // @ARouter注解中的path值,必须要以 / 开头(模仿阿里Arouter规范)
        if (EmptyUtils.isEmpty(path) || !path.startsWith("/")) {
            messager.printMessage(Diagnostic.Kind.ERROR, "@ARouter注解中的path值,必须要以 / 开头");
            return false;
        }

        // 比如开发者代码为:path = "/MainActivity",最后一个 / 符号必然在字符串第1位
        if (path.lastIndexOf("/") == 0) {
            // 架构师定义规范,让开发者遵循
            messager.printMessage(Diagnostic.Kind.ERROR, "@ARouter注解未按规范配置,如:/app/MainActivity");
            return false;
        }

        // 从第一个 / 到第二个 / 中间截取,如:/app/MainActivity 截取出 app 作为group
        String finalGroup = path.substring(1, path.indexOf("/", 1));

        // @ARouter注解中的group有赋值情况
        if (!EmptyUtils.isEmpty(group) && !group.equals(moduleName)) {
            // 架构师定义规范,让开发者遵循
            messager.printMessage(Diagnostic.Kind.ERROR, "@ARouter注解中的group值必须和子模块名一致!");
            return false;
        } else {
            bean.setGroup(finalGroup);
        }

        return true;
    }
}

APT generate dynamic routing parameter file

Under normal circumstances, the reception parameters are as follows:

Here Insert Picture Description

Components of, the received parameters as follows:
Here Insert Picture Description

  1. Statement parameter annotation

     @Target(ElementType.FIELD) // 该注解作用在属性之上
     @Retention(RetentionPolicy.CLASS)
     public @interface Parameter {
     
         // 不填写name的注解值表示该属性名就是key,填写了就用注解值作为key
         // 从getIntent()方法中获取传递参数值
         String name() default "";
     }
    
  2. Notes simulation method to generate

     public class MainActivity$$Parameter implements ParameterLoad {
       @Override
       public void loadParameter(Object target) {
         MainActivity t = (MainActivity)target;
         t.name = t.getIntent().getStringExtra("name");
         t.agex = t.getIntent().getStringExtra("agex");
       }
     }
    
  3. Implementation Notes parsing class

     @AutoService(Processor.class)
     @SupportedAnnotationTypes({Constants.PARAMETER_ANNOTATION_TYPES})
     @SupportedSourceVersion(SourceVersion.RELEASE_7)
     public class ParameterProcessor extends AbstractProcessor {
     
         private Elements elementUtils;
         private Types typeUtils;
         private Messager messager;
         private Filer filer;
     
         // 临时map存储,用来存放被@Parameter注解的属性集合,生成类文件时遍历
         // key:类节点, value:被@Parameter注解的属性集合
         private Map<TypeElement, List<Element>> tempParameterMap = new HashMap<>();
     
         @Override
         public synchronized void init(ProcessingEnvironment processingEnvironment) {
             super.init(processingEnvironment);
             elementUtils = processingEnvironment.getElementUtils();
             typeUtils = processingEnvironment.getTypeUtils();
             messager = processingEnvironment.getMessager();
             filer = processingEnvironment.getFiler();
         }
     
         @Override
         public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
             // 一旦有类之上使用@Parameter注解
             if (!EmptyUtils.isEmpty(set)) {
                 // 获取所有被 @Parameter 注解的 元素(属性)集合
                 Set<? extends Element> elements = roundEnvironment.getElementsAnnotatedWith(Parameter.class);
     
                 if (!EmptyUtils.isEmpty(elements)) {
                     // 解析元素
                     try {
                         // 赋值临时map存储,用来存放被注解的属性集合
                         valueOfParameterMap(elements);
                         // 生成类文件,如:
                         createParameterFile();
                         return true;
                     } catch (IOException e) {
                         e.printStackTrace();
                     }
                 }
                 return true;
             }
             return false;
         }
     
         private void createParameterFile() throws IOException {
             // 判断是否有需要生成的类文件
             if (EmptyUtils.isEmpty(tempParameterMap)) return;
             // 通过Element工具类,获取Parameter类型
             TypeElement activityType = elementUtils.getTypeElement(Constants.ACTIVITY);
             TypeElement parameterType = elementUtils.getTypeElement(Constants.PARAMETER_LOAD);
     
             // 参数体配置(Object target)
             ParameterSpec parameterSpec = ParameterSpec.builder(TypeName.OBJECT, Constants.PARAMETER_NAMR).build();
             for (Map.Entry<TypeElement, List<Element>> entry : tempParameterMap.entrySet()) {
                 // Map集合中的key是类名,如:MainActivity
                 TypeElement typeElement = entry.getKey();
                 // 如果类名的类型和Activity类型不匹配
                 if (!typeUtils.isSubtype(typeElement.asType(), activityType.asType())) {
                     throw new RuntimeException("@Parameter注解目前仅限用于Activity类之上");
                 }
     
                 // 获取类名
                 ClassName className = ClassName.get(typeElement);
                 // 方法体内容构建
                 ParameterFactory factory = new ParameterFactory.Builder(parameterSpec)
                         .setMessager(messager)
                         .setClassName(className)
                         .build();
     
                 // 添加方法体内容的第一行
                 factory.addFirstStatement();
     
                 // 遍历类里面所有属性
                 for (Element fieldElement : entry.getValue()) {
                     factory.buildStatement(fieldElement);
                 }
     
                 // 最终生成的类文件名(类名$$Parameter)
                 String finalClassName = typeElement.getSimpleName() + Constants.PARAMETER_FILE_NAME;
                 messager.printMessage(Diagnostic.Kind.NOTE, "APT生成获取参数类文件:" +
                         className.packageName() + "." + finalClassName);
     
                 // MainActivity$$Parameter
                 JavaFile.builder(className.packageName(), // 包名
                         TypeSpec.classBuilder(finalClassName) // 类名
                                 .addSuperinterface(ClassName.get(parameterType)) // 实现ParameterLoad接口
                                 .addModifiers(Modifier.PUBLIC) // public修饰符
                                 .addMethod(factory.build()) // 方法的构建(方法参数 + 方法体)
                                 .build()) // 类构建完成
                         .build() // JavaFile构建完成
                         .writeTo(filer); // 文件生成器开始生成类文件
             }
         }
     
         /**
          * 赋值临时map存储,用来存放被@Parameter注解的属性集合,生成类文件时遍历
          *
          * @param elements 被 @Parameter 注解的 元素集合
          */
         private void valueOfParameterMap(Set<? extends Element> elements) {
             for (Element element : elements) {
                 // 注解在属性之上,属性节点父节点是类节点
                 TypeElement enclosingElement = (TypeElement) element.getEnclosingElement();
                 // 如果map集合中的key:类节点存在,直接添加属性
                 if (tempParameterMap.containsKey(enclosingElement)) {
                     tempParameterMap.get(enclosingElement).add(element);
                 } else {
                     List<Element> fields = new ArrayList<>();
                     fields.add(element);
                     tempParameterMap.put(enclosingElement, fields);
                 }
             }
         }
     }
    

The method of generating member ParameterFactory

    public class ParameterFactory {

        // MainActivity t = (MainActivity) target;
        private static final String CONTENT = "$T t = ($T)target";
    
        // 方法体构建
        private MethodSpec.Builder methodBuidler;
    
        // Messager用来报告错误,警告和其他提示信息
        private Messager messager;
    
        // 类名,如:MainActivity
        private ClassName className;
    
        private ParameterFactory(Builder builder) {
            this.messager = builder.messager;
            this.className = builder.className;
    
            // 通过方法参数体构建方法体:public void loadParameter(Object target) {
            methodBuidler = MethodSpec.methodBuilder(Constants.PARAMETER_METHOD_NAME)
                    .addAnnotation(Override.class)
                    .addModifiers(Modifier.PUBLIC)
                    .addParameter(builder.parameterSpec);
        }
    
        /**
         * 添加方法体内容的第一行(MainActivity t = (MainActivity) target;)
         */
        public void addFirstStatement() {
            // 方法内容:MainActivity t = (MainActivity) target;
            methodBuidler.addStatement(CONTENT, className, className);
        }
    
        public MethodSpec build() {
            return methodBuidler.build();
        }
    
        /**
         * 构建方体内容,如:t.s = t.getIntent.getStringExtra("s");
         *
         * @param element 被注解的属性元素
         */
        public void buildStatement(Element element) {
            // 遍历注解的属性节点 生成函数体
            TypeMirror typeMirror = element.asType();
            // 获取 TypeKind 枚举类型的序列号
            int type = typeMirror.getKind().ordinal();
            // 获取属性名
            String fieldName = element.getSimpleName().toString();
            // 获取注解的值
            String annotationValue = element.getAnnotation(Parameter.class).name();
            // 判断注解的值为空的情况下的处理(注解中有name值就用注解值)
            annotationValue = EmptyUtils.isEmpty(annotationValue) ? fieldName : annotationValue;
            // 最终拼接的前缀:
            String finalValue = "t." + fieldName;
            // t.s = t.getIntent().
            String methodContent = finalValue + " = t.getIntent().";
    
            // TypeKind 枚举类型不包含String
            if (type == TypeKind.INT.ordinal()) {
                // t.s = t.getIntent().getIntExtra("age", t.age);
                methodContent += "getIntExtra($S, " + finalValue + ")";
            } else if (type == TypeKind.BOOLEAN.ordinal()) {
                // t.s = t.getIntent().getBooleanExtra("isSuccess", t.age);
                methodContent += "getBooleanExtra($S, " + finalValue + ")";
            } else {
                // t.s = t.getIntent.getStringExtra("s");
                if (typeMirror.toString().equalsIgnoreCase(Constants.STRING)) {
                    methodContent += "getStringExtra($S)";
                }
            }
    
            // 健壮代码
            if (methodContent.endsWith(")")) {
                // 添加最终拼接方法内容语句
                methodBuidler.addStatement(methodContent, annotationValue);
            } else {
                messager.printMessage(Diagnostic.Kind.ERROR, "目前暂支持String、int、boolean传参");
            }
        }
    
        public static class Builder {
    
            // Messager用来报告错误,警告和其他提示信息
            private Messager messager;
    
            // 类名,如:MainActivity
            private ClassName className;
    
            // 方法参数体
            private ParameterSpec parameterSpec;
    
            public Builder(ParameterSpec parameterSpec) {
                this.parameterSpec = parameterSpec;
            }
    
            public Builder setMessager(Messager messager) {
                this.messager = messager;
                return this;
            }
    
            public Builder setClassName(ClassName className) {
                this.className = className;
                return this;
            }
    
            public ParameterFactory build() {
                if (parameterSpec == null) {
                    throw new IllegalArgumentException("parameterSpec方法参数体为空");
                }
    
                if (className == null) {
                    throw new IllegalArgumentException("方法内容中的className为空");
                }
    
                if (messager == null) {
                    throw new IllegalArgumentException("messager为空,Messager用来报告错误、警告和其他提示信息");
                }
    
                return new ParameterFactory(this);
            }
        }
    }
  1. Use annotation class

     @ARouter(path = "/order/OrderMainActivity")
     public class OrderMainActivity extends AppCompatActivity {
     
         @Parameter
         String name;
     
         @Parameter(name = "agex")
         int age;
     
         @Override
         protected void onCreate(@Nullable Bundle savedInstanceState) {
             super.onCreate(savedInstanceState);
             setContentView(R.layout.order_main_activity);
             
             //调用生成的类
             new OrderMainActivity$$Parameter().loadParameter(this);
         }
    
Published 98 original articles · won praise 6 · views 20000 +

Guess you like

Origin blog.csdn.net/dirksmaller/article/details/103930775