当前位置:   article > 正文

组件化之组件通讯和APT、JavaPoet使用(二)_javapoet和反射

javapoet和反射

目录

  • 模块间交互
  • APT介绍与使用
  • APT高阶用法JavaPoet

模块间交互

常见的交互方式

1)EventBus一对一通讯,会造成Bean对象泛
2)反射技术 维护成本较高,高版本容易出现@hide限
3)隐式意图 维护成本较高,action比较难以维护
4) 广播 7.0后需要动态注册
5)类加载器 需要全类名路径

解决方案
类加载模式

在这里插入图片描述

public void jumpApp(View v){
    try {
        //通过全类名的方式进行跳转
        Class<?> clzz = Class.forName("com.canjun.myapplication.MainActivity");
        Intent intent = new Intent(this,clzz);
        startActivity(intent);
    }catch (Exception e){

    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
全局map记录的方式

在这里插入图片描述

  1. 在公共模块(common模块)添加全局记录类

     /**
      * RecorderPathManager
      * 记录全局的path信息
      *
      * @author zfc
      * @date 2020-01-09
      */
     public class RecorderPathManager {
     
         private static Map<String, List<PathBean>> paths = new HashMap<>();
     
         /**
          * 根据组名和路径名记录字节码信息
          * @param groupName
          * @param pathName
          * @param clazz
          */
         public static void joinGroup(String groupName,String pathName,Class clazz){
             List<PathBean> path = paths.get(groupName);
             if(path==null){
                 //添加
                 path = new ArrayList<>();
                 paths.put(groupName,path);
             }else {
                 for (PathBean p: path){
                     if(p.getPath().equals(pathName)){
                         return;
                     }
                 }
             }
             path.add(new PathBean(pathName,clazz));
         }
     
         /**
          * 获取目标字节码对象
          * @param groupName 组名
          * @param pathName 路径名
          * @return
          */
         public static Class getTargetClass(String groupName,String pathName){
             List<PathBean> path = paths.get(groupName);
             if(path==null){
                 return null;
             }
             for (PathBean p: path){
                 if(p.getPath().equals(pathName)){
                     return p.getClzz();
                 }
             }
     
             return null;
         }
     }
    
     /**
      * PathBean
      *
      * 记录Activity字节码及其路径
      * 例如
      *      path:'order/OrderMainActivity'
      *      clzz: OrderMainActivity.class
      *
      * @author zfc
      * @date 2020-01-09
      */
     public class PathBean {
     
         private String path;
     
         private Class clzz;
     
         public PathBean(String path, Class clzz) {
             this.path = path;
             this.clzz = clzz;
         }
     
         public String getPath() {
             return path;
         }
     
         public void setPath(String path) {
             this.path = path;
         }
     
         public Class getClzz() {
             return clzz;
         }
     
         public void setClzz(Class clzz) {
             this.clzz = clzz;
         }
     }
    
    • 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
  2. 在应用启动时,添加需要记录的字节码对象

     /**
      * MyApp
      *
      * @author zfc
      * @date 2020-01-09
      */
     public class MyApp extends BaseApplication {
     
         @Override
         public void onCreate() {
             super.onCreate();
             //注册activity
             RecorderPathManager.joinGroup("app","MainActivity",MainActivity.class);
             RecorderPathManager.joinGroup("order","OrderMainActivity", OrderMainActivity.class);
             RecorderPathManager.joinGroup("personal","PersonalMainActivity", PersonalMainActivity.class);
         }
     }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
  3. 在页面跳转时,使用字节码对象

      try {
         Class<?> clzz = RecorderPathManager.getTargetClass("app","MainActivity");
         Intent intent = new Intent(this, clzz);
         startActivity(intent);
     }catch (Exception e){
    
     }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

APT介绍与使用

APT是什么

在这里插入图片描述

结构体语言

语言元素分类
在这里插入图片描述

在这里插入图片描述

常用的API

在这里插入图片描述

在这里插入图片描述

APT基本使用
  1. 环境描述

    a.创建java library 名为compiler

    b.为compiler添加依赖

      // 注册注解,并对其生成META-INF的配置信息,rc2在gradle5.0后有坑
     // As-3.2.1 + gradle4.10.1-all + auto-service:1.0-rc2
     // implementation 'com.google.auto.service:auto-service:1.0-rc2'
    
     // As-3.4.1 + gradle5.1.1-all + auto-service:1.0-rc4
     compileOnly'com.google.auto.service:auto-service:1.0-rc4'
     annotationProcessor'com.google.auto.service:auto-service:1.0-rc4'
    
     implementation project(':annotation')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
  2. 创建注解处理器

     /*
      * 通过autoService通过生成文件
      */
     @AutoService(Processor.class)
     
     @SupportedAnnotationTypes({"com.canjun.annotation.ARouter"})
     @SupportedSourceVersion(SourceVersion.RELEASE_7)
     @SupportedOptions({"content"}) //外部传入的参数
     public class ARouterProcessor extends AbstractProcessor {
     
         /**
          * 操作Element的工具类
          */
         private Elements elementUtils;
     
         /**
          * 类信息工具类
          */
         private Types typesUtils;
     
         /**
          * 日志信息输出工具类
          */
         private Messager messager;
     
         /**
          * 文件生成器
          */
         private Filer filer;
     
         //初始化工作
         @Override
         public synchronized void init(ProcessingEnvironment processingEnv) {
             super.init(processingEnv);
             elementUtils = processingEnv.getElementUtils();
             typesUtils = processingEnv.getTypeUtils();
             messager = processingEnv.getMessager();
             filer = processingEnv.getFiler();
             
             //可以获取外部模块传入的参数
             //传参方式见下小结
             String content = processingEnv.getOptions().get("content");
             messager.printMessage(Diagnostic.Kind.NOTE,content);
         }
     //
     //    //需要处理的注解类型
     //    @Override
     //    public Set<String> getSupportedAnnotationTypes() {
     //        return super.getSupportedAnnotationTypes();
     //    }
     //
     //    //jdk版本去编辑
     //    @Override
     //    public SourceVersion getSupportedSourceVersion() {
     //        return super.getSupportedSourceVersion();
     //    }
     //
     //    //接收外部参数
     //    @Override
     //    public Set<String> getSupportedOptions() {
     //        return super.getSupportedOptions();
     //    }
     
         @Override
         public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
     }
    
    • 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
  3. 通过AndroidModule向java library compiler传入参数

     // 在gradle文件中配置选项参数值(用于APT传参接收)
     // 切记:必须写在defaultConfig节点下
      javaCompileOptions {
         annotationProcessorOptions {
             arguments = [content : 'hello apt']
         }
     }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
  4. AndroidModule使用注解处理器

    a.gradle中依赖的声明

      implementation project(':annotation')
     //使用注解处理器
     annotationProcessor project(':compiler')
    
    • 1
    • 2
    • 3

    b.Activity中使用注解

     @ARouter(path="/app/MainActivity")
     public class MainActivity extends AppCompatActivity {
         ...
         ...
     }
    
    • 1
    • 2
    • 3
    • 4
    • 5
  5. 注解处理中核心方法的实现

     @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
    
        if(annotations == null){
            return false;
        }
    
        messager.printMessage(Diagnostic.Kind.NOTE,annotations.toString());
    
        //获取被注解的类对象
        Set<? extends Element> elements = roundEnv.getElementsAnnotatedWith(ARouter.class);
        for (Element e:elements){
            //获取包名
            String pkgName = elementUtils.getPackageOf(e).getQualifiedName().toString();
            //获取类名
            String className = e.getSimpleName().toString();
    
            messager.printMessage(Diagnostic.Kind.NOTE,pkgName + ">>" + className);
    
            //生成ARouter文件
            String finalClassName = className+"$$ARouter";
    
    
            try {
                JavaFileObject sourceFile =  filer.createSourceFile(pkgName+"."+finalClassName);
                Writer writer = sourceFile.openWriter();
                //设置包名
                writer.write("package "+pkgName + ";\n");
                writer.write("public class "+finalClassName+" {\n");
                writer.write("public static Class<?> findTargetClass(String pathName){\n");
                //获取注解的path的value(注意)
                String path = e.getAnnotation(ARouter.class).path();
                writer.write("if(pathName.equalsIgnoreCase(\""+path+"\")){\n");
                writer.write("return "+className+".class;\n");
                writer.write("}\n");
                writer.write("return null;\n");
                writer.write("}\n");
                writer.write("}\n");
                writer.close();
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
    
        return true;
    }
    
    • 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
  6. 验证注解处理器生成的类

    通过build->make project
    在这里插入图片描述

使用autoService注解 注解处理器,会在如下图中的位置生成注册信息。
在这里插入图片描述

APT高阶用法和JavaPoet

JavaPoet概述

JavaPoet官往地址

JavaPoet是什么

在这里插入图片描述

JavaPoet运行环境

在这里插入图片描述

implementation 'com.squareup:javapoet:1.9.0'

// 注册注解,并对其生成META-INF的配置信息,rc2在gradle5.0后有坑
// As-3.2.1 + gradle4.10.1-all + auto-service:1.0-rc2
// implementation 'com.google.auto.service:auto-service:1.0-rc2'

// As-3.4.1 + gradle5.1.1-all + auto-service:1.0-rc4
compileOnly'com.google.auto.service:auto-service:1.0-rc4'
annotationProcessor'com.google.auto.service:auto-service:1.0-rc4'
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
JavaPoet常用类

在这里插入图片描述

javaPoet格式化字符串

在这里插入图片描述

使用javaPoet
要求 生成如下格式的代码
   package com.canjun.myapplication;
   public class MainActivity$$ARouter {

       public static Class findTargetClass(String name){
           if(name.equalsIgnoreCase("/app/MainActivity")){
               return MainActivity.class;
           }
           return null;
       }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
javaPoet编写内容如下:
@AutoService(Processor.class)
@SupportedAnnotationTypes({"com.canjun.annotation.ARouter"})
@SupportedSourceVersion(SourceVersion.RELEASE_7)
@SupportedOptions({"content"})
public class ARouterProcessor extends AbstractProcessor {

    private Elements elementUtils;
    private Types typeUtils;
    private Messager messager;
    private Filer filer;

    @Override
    public synchronized void init(ProcessingEnvironment processingEnv) {
        super.init(processingEnv);
        elementUtils = processingEnv.getElementUtils();
        typeUtils = processingEnv.getTypeUtils();
        messager = processingEnv.getMessager();
        filer = processingEnv.getFiler();
        Map<String, String> options = processingEnv.getOptions();
        String content = options.get("content");
        messager.printMessage(Diagnostic.Kind.NOTE, content);
    }

    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
       if(annotations==null||annotations.isEmpty()){
           return false;
       }

       //获取被ARouter注解的类
        Set<? extends Element> elements = roundEnv.getElementsAnnotatedWith(ARouter.class);

       for (Element e : elements){
           //获取e的包名
           String pkgName = elementUtils.getPackageOf(e).getQualifiedName().toString();
           //获取类名
           String className = e.getSimpleName().toString();

           String newFileName = className+"$$ARouter";
           //通过javaPoet写新生成的文件
           //javaPoet项目地址https://github.com/square/javapoet

           try {
               String pathName = e.getAnnotation(ARouter.class).path();
               MethodSpec methodSpec = MethodSpec.methodBuilder("findTargetClass")
                       .addModifiers(Modifier.PUBLIC, Modifier.STATIC)
                       .returns(Class.class)
                       .addParameter(String.class, "name")
                       //需要注意的是 语句中的参数 不需要显式添加“;”
                       .addStatement(" if(name.equalsIgnoreCase($S)){\n" +
                               "                       return $T.class;\n" +
                               "                   }\n" +
                               "                   return null", pathName, ClassName.get((TypeElement)e))
                       .build();

               TypeSpec typeSpec = TypeSpec.classBuilder(newFileName)
                       .addModifiers(Modifier.PUBLIC, Modifier.FINAL)
                       .addMethod(methodSpec)
                       .build();

               JavaFile javaFile = JavaFile.builder(pkgName,typeSpec)
                       .build();


               javaFile.writeTo(filer);
           } catch (IOException ex) {
               ex.printStackTrace();
           }
       }

        return true;
    }

}
  • 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

生成结果:

lf7keU.png

lf7ZFJ.png

声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:【wpsshop博客】
推荐阅读
  

闽ICP备14008679号