• ARouter使用自定义注解处理器,自动生成跳转Activity的代码,避免手动填写和管理path


    大家都知道ARouter要跳转目标Activity需要两步:

    1.在Activity上添加Route注解

    // Add annotations on pages that support routing (required)
    // The path here needs to pay attention to need at least two levels : /xx/xx
    @Route(path = "/test/activity")
    public class YourActivity extend Activity {
        ...
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    2.执行ARouter.getInstance().build("/test/activity").navigation()方法即可实现跳转

    // 1. Simple jump within application (Jump via URL in 'Advanced usage')
    ARouter.getInstance().build("/test/activity").navigation();
    
    // 2. Jump with param bundle
    ARouter.getInstance().build("/test/1")
                .withBundle("key1", bundle)
                .navigation();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    这就导致了我们需要去管理大量的path字符串,为什么ARouter不能在编译时期帮我们生成一个中间类去管理这些path字符串呢?

    既然官方不支持那就自己来做一个吧,整体思路如下:

    1.定义两个Activity并添加Route注解

    @Route(path = "/login/LoginActivity")
    class LoginActivity : AppCompatActivity() {
    
    • 1
    • 2
    @Route(path = "/login/RegisterActivity")
    class RegisterActivity :BaseActivity() {
    
    • 1
    • 2

    2.通过自定义注解处理器,处理所有带Route注解的类,并取出注解里的path变量值,生成一个中间类用于管理所有的path,并封装跳转的方法,生成的中间类如下:

    package com.agilezhu.processor.generate;
    
    import android.os.Bundle;
    import java.lang.String;
    
    public final class ARouterPage {
      LoginActivity LoginActivity;
    
      RegisterActivity RegisterActivity;
    
      public ARouterPage() {
        LoginActivity.path = "/login/LoginActivity";
        RegisterActivity.path = "/login/RegisterActivity";
      }
    
      public static class LoginActivity {
        public static String path;
    
        static {
          path= "/login/LoginActivity";
        }
    
        public static void navigation(String key, Bundle params) {
          com.alibaba.android.arouter.launcher.ARouter.getInstance().build(path).withBundle(key,params).navigation();
        }
    
        public static void navigation() {
          com.alibaba.android.arouter.launcher.ARouter.getInstance().build(path).navigation();
        }
      }
    
      public static class RegisterActivity {
        public static String path;
    
        static {
          path= "/login/RegisterActivity";
        }
    
        public static void navigation(String key, Bundle params) {
          com.alibaba.android.arouter.launcher.ARouter.getInstance().build(path).withBundle(key,params).navigation();
        }
    
        public static void navigation() {
          com.alibaba.android.arouter.launcher.ARouter.getInstance().build(path).navigation();
        }
      }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48

    3.使用方法

    //不带参数
    ARouterPage.LoginActivity.navigation()
    //带Bundle类型参数
    ARouterPage.RegisterActivity.navigation("params",Bundle())
    //也可以使用原有ARouter跳转方式携带各种参数
    ARouter.getInstance().build(ARouterPage.LoginActivity.path).withBoolean("key",true).navigation();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    有了注解处理器相当于自动帮我们生成了一个管理所有path的类:

    • 可以通过类似调用目标Activity的方式进行跳转;
    • 简化了ARouter跳转Acticity的代码;
    • 每次添加、修改、删除对应的类,都不需要手动修改管理类代码;

    注解处理器开发过程

    1. 添加一个java 类型Module
      在这里插入图片描述

    2. build.gradle 内容如下:

      plugins {
          id 'java-library'
      }
      dependencies {
          implementation fileTree(dir: 'libs', include: ['*.jar'])
          annotationProcessor 'com.google.auto.service:auto-service:1.0-rc7'//auto-service本身也是个注解处理器
          implementation 'com.google.auto.service:auto-service:1.0-rc7'//注解 processor 类,并对其生成 META-INF 的配置信息
          implementation 'com.squareup:javapoet:1.13.0' //通过类调用的形式来生成java代码,避免手动拼接字符串
          implementation "com.alibaba:arouter-annotation:1.0.6"
      }
      
      
      java {
          sourceCompatibility = JavaVersion.VERSION_1_7
          targetCompatibility = JavaVersion.VERSION_1_7
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
    3. 注解处理器核心类:

      package com.agilezhu.processor;
      
      import com.alibaba.android.arouter.facade.annotation.Route;
      import com.google.auto.service.AutoService;
      import com.squareup.javapoet.ClassName;
      import com.squareup.javapoet.CodeBlock;
      import com.squareup.javapoet.JavaFile;
      import com.squareup.javapoet.MethodSpec;
      import com.squareup.javapoet.TypeSpec;
      
      import java.util.LinkedHashSet;
      import java.util.Set;
      
      import javax.annotation.processing.AbstractProcessor;
      import javax.annotation.processing.Filer;
      import javax.annotation.processing.Messager;
      import javax.annotation.processing.ProcessingEnvironment;
      import javax.annotation.processing.Processor;
      import javax.annotation.processing.RoundEnvironment;
      import javax.lang.model.SourceVersion;
      import javax.lang.model.element.Element;
      import javax.lang.model.element.Modifier;
      import javax.lang.model.element.TypeElement;
      import javax.lang.model.util.Elements;
      import javax.tools.Diagnostic;
      
      /**
       * Generate ARouterPage.java for ARouter
       */
      @AutoService(Processor.class)
      public class ARouterProcessor extends AbstractProcessor {
          private Filer mFiler; //文件相关工具类:用于保存生成的java类文件
          private Elements mElementUtils; //元素相关工具类:用于获取java类文件
          private Messager mMessager;//用于打印日志
      
          @Override
          public synchronized void init(ProcessingEnvironment processingEnvironment) {
              super.init(processingEnvironment);
              mFiler = processingEnv.getFiler();
              mElementUtils = processingEnv.getElementUtils();
              mMessager = processingEnv.getMessager();
          }
      
          @Override
          public Set<String> getSupportedAnnotationTypes() {
              //返回该注解处理器能够处理哪些注解
              Set<String> types = new LinkedHashSet<>();
              types.add(Route.class.getName());
              return types;
          }
      
          @Override
          public SourceVersion getSupportedSourceVersion() {
              //返回当前注解处理器支持的java版本号
              return SourceVersion.latest();
          }
      
          @Override
          public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
              if (set == null || set.size() == 0) {
                  return false;
              }
              //将要生成的java完整类名
              String targetClassName = "ARouterPage";
              String packageName = "com.agilezhu.processor.generate";
      
              //创建方法(构造方法)
              MethodSpec.Builder bindMethodBuilder = MethodSpec.methodBuilder("")
                      .addModifiers(Modifier.PUBLIC);
      
              //创建类
              TypeSpec.Builder aRouterPageClassBuilder = TypeSpec.classBuilder(targetClassName)
                      .addModifiers(Modifier.PUBLIC, Modifier.FINAL);
      
              //获取所有的源码文件
              Set<? extends Element> elements = roundEnvironment.getRootElements();
              for (Element element : elements) {
                  if (!(element instanceof TypeElement)) {//判断是否class类
                      continue;
                  }
                  //转换成class类型
                  TypeElement typeElement = (TypeElement) element;
                  //当前文件的类名
                  String classSimpleName = element.getSimpleName().toString();
                  Route routeAnnotation = element.getAnnotation(Route.class);
                  if (routeAnnotation == null) {
                      continue;
                  }
                  mMessager.printMessage(Diagnostic.Kind.WARNING, "myProcess=====>>>>>" + classSimpleName);
      
                  ClassName innerClassName = ClassName.get(packageName, targetClassName, classSimpleName);
      
                  try {
                      aRouterPageClassBuilder.addField(innerClassName, classSimpleName)
                              .addType(TypeSpec.classBuilder(innerClassName.simpleName())
                                      .addModifiers(Modifier.STATIC, Modifier.PUBLIC)
                                      .addField(String.class, "path", Modifier.PUBLIC, Modifier.STATIC)
                                      .addStaticBlock(CodeBlock.builder().addStatement("path= \"" + routeAnnotation.path() + "\"").build())
                                      .addMethod(MethodSpec
                                              .methodBuilder("navigation")
                                              .addParameter(String.class,"key")
                                              .addParameter(ClassName.get("android.os","Bundle"), "params")
                                              .addStatement("com.alibaba.android.arouter.launcher.ARouter.getInstance().build(path).withBundle(key,params).navigation()")
                                              .addModifiers(Modifier.PUBLIC, Modifier.STATIC)
                                              .build())
                                      .addMethod(MethodSpec
                                              .methodBuilder("navigation")
                                              .addStatement("com.alibaba.android.arouter.launcher.ARouter.getInstance().build(path).navigation()")
                                              .addModifiers(Modifier.PUBLIC, Modifier.STATIC)
                                              .build())
                                      .build());
                  } catch (Exception e) {
                      e.printStackTrace();
                  }
      
                  //构造方法中添加初始化代码
                  bindMethodBuilder.addStatement(classSimpleName + ".path = \"" + routeAnnotation.path() + "\"");
              }
              aRouterPageClassBuilder.addMethod(bindMethodBuilder.build());
              //创建java文件
              JavaFile bindProxyFile = JavaFile
                      .builder(packageName, aRouterPageClassBuilder.build())
                      .build();
              try {
                  //保存java类文件
                  bindProxyFile.writeTo(mFiler);
              } catch (Throwable e) {
                  e.printStackTrace();
              }
              return false;
          }
      
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36
      • 37
      • 38
      • 39
      • 40
      • 41
      • 42
      • 43
      • 44
      • 45
      • 46
      • 47
      • 48
      • 49
      • 50
      • 51
      • 52
      • 53
      • 54
      • 55
      • 56
      • 57
      • 58
      • 59
      • 60
      • 61
      • 62
      • 63
      • 64
      • 65
      • 66
      • 67
      • 68
      • 69
      • 70
      • 71
      • 72
      • 73
      • 74
      • 75
      • 76
      • 77
      • 78
      • 79
      • 80
      • 81
      • 82
      • 83
      • 84
      • 85
      • 86
      • 87
      • 88
      • 89
      • 90
      • 91
      • 92
      • 93
      • 94
      • 95
      • 96
      • 97
      • 98
      • 99
      • 100
      • 101
      • 102
      • 103
      • 104
      • 105
      • 106
      • 107
      • 108
      • 109
      • 110
      • 111
      • 112
      • 113
      • 114
      • 115
      • 116
      • 117
      • 118
      • 119
      • 120
      • 121
      • 122
      • 123
      • 124
      • 125
      • 126
      • 127
      • 128
      • 129
      • 130
      • 131
      • 132
      • 133
    4. 业务模块中引用:

      kapt project(path: ':lib:processor') //这里用的kapt处理Kotlin代码
      
      • 1
    5. 重新编译后,在当前模块build/generated/source/kapt/debug/com/agilezhu/processor/generate/ARouterPage.java路径下就能看到生成的类

    模块代码下载

  • 相关阅读:
    测试人进阶技能:单元测试报告应用指南
    计算机组成原理学习笔记:主机三件套硬件部件
    MySQL中的死锁预防和解决
    顺序表(c++类模板实现)
    顾客点餐系统-----操作菜品JDBC代码的编写(1)
    第五章 循环结构程序设计
    图论01-【无权无向】-图的基本表示-邻接矩阵/邻接表
    springboot+java+vue大学生求职招聘就业岗位匹配推荐系统
    Cesium:城市建筑白膜制作与加载全流程解析
    2022年前端技术发展趋势
  • 原文地址:https://blog.csdn.net/guangdeshishe/article/details/126195119