组件化之组件通讯和APT、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){

    }
}
全局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;
         }
     }
    
  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);
         }
     }
    
  3. 在页面跳转时,使用字节码对象

      try {
         Class<?> clzz = RecorderPathManager.getTargetClass("app","MainActivity");
         Intent intent = new Intent(this, clzz);
         startActivity(intent);
     }catch (Exception e){
    
     }
    

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')
    
  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) {
     }
    
  3. 通过AndroidModule向java library compiler传入参数

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

    a.gradle中依赖的声明

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

    b.Activity中使用注解

     @ARouter(path="/app/MainActivity")
     public class MainActivity extends AppCompatActivity {
         ...
         ...
     }
    
  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;
    }
    
  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'
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;
       }
    }
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;
    }

}

生成结果:

lf7keU.png

lf7ZFJ.png

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值