赞
踩
1、APT(注解处理器)介绍
APT(Annotation Processing Tool)是一种处理注释的工具,它对源代码文件进行检测找出其中的Annotation,根据注解主动生成代码,如果想要自定义注解处理器能够正常运行,必须要通过APT工具来进行处理。
也可以这样理解,只有通过申明APT工具后,程序在编译期间自定义注解处理器才能执行
通过来讲:根据规则,帮我们自动生成代码,生成类文件
Google提供了APT的库(Java库),后面会介绍如何导入使用
2、Element程序元素
3、常用API
属性名 | 说明 |
---|---|
getEnclosedElements() | 返回该元素直接包含的子元素 |
getEnclosingElement() | 返回包含该element的父element,与上一个方法相反 |
getKind() | 返回element的类型,判断是哪种element |
getModifiers() | 获取修饰关键字,如public static final等关键字 |
getSimpleName() | 获取名字,不带包名 |
getQualifiedName() | 获取全名,如果是类的话,包含完整的包名路径 |
getParameters() | 获取方法的参数元素,每个元素是一个VariableElement |
getReturnType() | 获取方法的返回值 |
getConstantValue() | 如果属性变量被final修饰,则可以使用该方法获取它的值 |
4、APT的开发环境
// 注册注解,并对其生成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'
// 最新的Android Studio + 最新的auto-service
// As-4.0.1 + gradle-6.1.1-all + auto-service:1.0-rc7
implementation 'com.google.auto.service:auto-service:1.0-rc7'
annotationProcessor'com.google.auto.service:auto-service:1.0-rc7'
5、JavaPoet
square公司的产品,OKhttp也是他们的产品,(#.#),square/javapoet
JavaPoet的使用,可以查看github上的demo
JavaPoet是square推出的开源的Java源代码生成框架,提供Java Api生成.java的源文件,使用方法也是符合我们日常书写习惯的Java面向对象OOP语法,可以很方便的时候它根据注解生成对应的代码,通过这种自动化生成代码的方式,可以让我们用更加简洁优雅的方式替代繁琐冗杂的重复工作
// 通过类调用的形式来生成Java代码(用来生成指定JAVA代码)
implementation 'com.squareup:javapoet:1.13.0'
类对象 | 说明 |
---|---|
MethodSpec | 代表一个构造函数或者方法声明 |
TypeSpec | 代表一个类、接口、或者枚举类型 |
FieldSpec | 代表一个成员变量,一个字段声明 |
JavaFile | 包含一个顶级类的Java文件 |
ParameterSpec | 用来创建参数 |
AnnotationSpec | 用来创建注解 |
ClassName | 用来包装一个类 |
TypeName | 类型,如在添加返回值类型是使用TypeName.VOID |
$L:字面量,如:"int value = $L", 1
$S:字符串,如:"$S","hello"
$T:类、接口,如:"$T",MainActivity
$N:变量,如:"user.$N", user.name
组件的目的就是解耦,各个Module之间没有相互依赖,但是组件之间还是会存在相互跳转
1、各个Module中的Activity互相跳转,可以使用全类名的方式使用startActivity()进行Activity之间的跳转
2、上一节讲到,将每个Module中的Activity封装到各个组代表的RouterBean的List集合中,然后根据 组名 将List集合封装到Map集合中
这一节我们将使用 注解 + APT(注解处理器) + JavaPoet将第二种方式进行的重复工作(重复代码)使用APT工具来帮我们自动生成,只需要在需要跳转的Activity上加上规定的注解,然后APT工具就能帮助我们自动完成封装代码的书写
1、annotation库,存储所有的注解和RouterBean
2、annotation_processor,用来处理注解
3、annotation_api,书写公共的接口,路由管理类等
接下来将上述的库做一个引入
// 引入注解中RouterBean对象(java项目才有javax.lang包)
implementation project(':annotation')
// 每个功能子模块既然都要生成APT源文件,而且又是所有模块依赖的公共库
// 那么公共基础库依赖路由annotation_api就能向每个子模块提供开放api了
// 路由对外开放api模块
api project(':annotation_api')
// 导入公共库
implementation project(':common_library')
// 注解
implementation project(':annotation')
// 注解处理器
annotationProcessor project(':annotation_processor')
// APT
// As-4.0.1 + gradle6.1.1-all + auto-service:1.0-rc7
implementation 'com.google.auto.service:auto-service:1.0-rc7'
annotationProcessor'com.google.auto.service:auto-service:1.0-rc7'
// 通过类调用的形式来生成Java代码(用来生成指定JAVA代码)
implementation 'com.squareup:javapoet:1.13.0'
// 引入annotation,让注解处理器-处理注解
implementation project(':annotation')
最后为了防止build控制台中文乱码
// java控制台输出中文乱码
tasks.withType(JavaCompile) {
options.encoding = "UTF-8"
}
如果操作的代码就懒得写在这里了,可以去github上把源代码下载下来看,┭┮﹏┭┮
组件化结构搭建代码
组件化结构搭建代码
组件化结构搭建代码
我们把注解文件贴一下吧,我们需要使用的注解是用在类之上的,并且是为了生成处理逻辑的源码,需要被打包在apk中
/** * <strong>Activity使用的布局文件注解</strong> * <ul> * <li>@Target(ElementType.TYPE) // 接口、类、枚举、注解</li> * <li>@Target(ElementType.FIELD) // 属性、枚举的常量</li> * <li>@Target(ElementType.METHOD) // 方法</li> * <li>@Target(ElementType.PARAMETER) // 方法参数</li> * <li>@Target(ElementType.CONSTRUCTOR) // 构造函数</li> * <li>@Target(ElementType.LOCAL_VARIABLE)// 局部变量</li> * <li>@Target(ElementType.ANNOTATION_TYPE)// 该注解使用在另一个注解上</li> * <li>@Target(ElementType.PACKAGE) // 包</li> * <li>@Retention(RetentionPolicy.RUNTIME) <br>注解会在class字节码文件中存在,jvm加载时可以通过反射获取到该注解的内容</li> * </ul> * * 生命周期:SOURCE < CLASS < RUNTIME * 1、一般如果需要在运行时去动态获取注解信息,用RUNTIME注解 * 2、要在编译时进行一些预处理操作,如ButterKnife,用CLASS注解。注解会在class文件中存在,但是在运行时会被丢弃 * 3、做一些检查性的操作,如@Override,用SOURCE源码注解。注解仅存在源码级别,在编译的时候丢弃该注解 */ @Target(ElementType.TYPE) // 该注解作用在类之上 @Retention(RetentionPolicy.CLASS) // 要在编译时进行一些预处理操作,注解会在class文件中存在 public @interface ARouter { // 详细路由路径(必填),如:"/app/MainActivity" String path(); // 路由组名(选填,如果开发者不填写,可以从path中截取出来) String group() default ""; }
简单的看下如何使用吧
1、在Activity上加上注解
@ARouter(path = "/app/MainActivity")
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
2、调用,如果实在app Module中,因为正式打包的时候,会将其他Module作为Library引入到app Module中,所以app中可以直接使用生成的类
private void jumpOrder() { // 最终集成化模式,所有子模块app/order/personal通过APT生成的类文件都会打包到apk里面, // 不用担心找不到 ARouter$$Group$$order group$$order = new ARouter$$Group$$order(); Map<String, Class<? extends ARouterLoadPath>> groupMap = group$$order.loadGroup(); // 通过order组名获取对应路由路径对象 Class<? extends ARouterLoadPath> orderClazz = groupMap.get("order"); if (orderClazz == null) return; // 类加载动态加载路由路径对象 try { ARouter$$Path$$order path$$order = (ARouter$$Path$$order) orderClazz.newInstance(); Map<String, RouterBean> pathMap = path$$order.loadPath(); RouterBean bean = pathMap.get("/order/OrderMainActivity"); if (bean == null) return; Class<?> targetClass = bean.getClazz(); jumpActivity(targetClass); } catch (IllegalAccessException | InstantiationException e) { e.printStackTrace(); } } private void jumpActivity(Class<?> clazz) { Intent intent = new Intent(this, clazz); intent.putExtra("name", "张三"); intent.putExtra("age", 100); startActivity(intent); }
上述代码就是我们正常使用APT帮我们生成的类去处理跳转逻辑,但是这种方式只适用于App Module跳转到其他Module,其他Module之间因为是完全解耦的,所以没法使用上述代码来进行跳转。
因此我们需要将上述的逻辑抽取出来到RouterManager中(RouterManger是放在annotation_api中,所有Module都能方法),使用路由管理器来处理上述的逻辑实现跳转,路由管理器的实现请到github下载源码查看。
路由管理器的使用,只需要将 上下文对象和 注册的 Path路径(/app/MainActivity) 传递给路由管理器,就帮我们处理了上述复杂的跳转逻辑
RouterManager.getInstance()
.build(RouterClassConstants.ORDER_OrderMainActivity)
.navigation(this);
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。