先把图放上来
这是Android组件化设计 — Gradle的神奇之处中的关于组件化的架构图,其中,组件1 … 组件4之前是不能相互依赖的,那么如果组件1想要调起组件2,只能通过基础层组件的路由能力。
在组件之前没有依赖的情况下,相互调用,那么可以通过类加载的方法,例如app壳想要调起注册模块,那么可以拿到注册模块的RegisterActivity的全类名,通过类加载的方式启动
fun jump(view: View) {
//com.study.register.RegisterActivity
//
val RegisterActivity = Class.forName("com.study.register.RegisterActivity")
startActivity(Intent(this,RegisterActivity))
}
或者可以通过注册路由表的方式,将所有的Activity的类信息注册到全局的Map中,如果存在成百的Actiivty,需要每个Activity手动去注册。
那么有没有一种方式,在编译的过程中就能拿到全部的类信息,注册到路由表中,避免手动注册这种方式
APT是注解处理工具,用于编译期在源代码中查找注解,根据注解生成新的类 函数;像Eventus、ButterKnife、ARouter都是编译期生成新的类,像EventBus是采用传统的生成代码方式,直接写字符串生成
传统方式
//1 先写包名 直接write
package com.study.modulelization
//2 再写类名
class HttpConfig {
//3 如果有方法 就再写方法名
companion object{
private const val DEBUG = "http://106.108.2.3//test-baidu.com"
private const val RELEASE = "http://106.108.2.3//baidu.com"
}
}
而像ButterKnife、ARouter采用的是JavaPoet方式,引入了面向对象的思想,跟传统方式相反,不如传统方式的可读性强
@Retention(AnnotationRetention.BINARY)
@Target(AnnotationTarget.TYPE)
annotation class LayRouter(
val group:String,
val path:String = ""
)
Kotlin中的注解,跟Java中的注解类似,在自定义注解时,需要声明元注解;
其中Retention代表注解存在的时期,SOURCE(源码时期)、BINARY(编译期,跟Java区分,Java编译期为Class)、RUNTIME(运行时)
Target为声明作用的对象,TYPE(类、接口等)、FUNCTION(函数,但不包含构造方法)、CONSTRUCTOR(构造方法)、PROPERTY_GETTER / PROPERTY_SETTER(get set方法)、FIELD(属性)
在声明注解之后,需要注解处理器来处理注解,在系统编译时,会从全部的代码中查找自定义的注解,生成代码,那么注解处理器相当于一个服务,在后台运行,检测代码,因此需要做一些配置
layout_compiler # build.gradle
dependencies {
//背后的服务
annotationProcessor 'com.google.auto.service:auto-service:1.0-rc4'
//JavaPoet
implementation "com.squareup:javapoet:1.13.0"
//要处理的注解
implementation project(path: ':lay_router')
}
谷歌的AutoService可以在编译时在后台检测代码,查找自定义的注解
@AutoService(Processor::class)
class AnnotationProcessor : AbstractProcessor() {
//操作Element的工具类(类、函数、属性等)
private var elementTool:Elements? = null
//类信息操作类 继承 实现 等实现方式
private var typeTool:Types? = null
//日志打印
private var message:Messager? = null
//文件输出
private var filer:Filer? = null
//支持的注解类型,就是我们自定义的注解
override fun getSupportedAnnotationTypes(): MutableSet<String> {
return mutableSetOf(LayRouter::class.java.canonicalName)
}
//支持的Java版本 Java 1.8
override fun getSupportedSourceVersion(): SourceVersion {
return SourceVersion.RELEASE_8
}
//支持的参数选项,就是从app壳传递到注解处理器的参数
override fun getSupportedOptions(): MutableSet<String> {
return mutableSetOf("moduleName")
}
override fun init(processingEnv: ProcessingEnvironment?) {
super.init(processingEnv)
elementTool = processingEnv!!.elementUtils
typeTool = processingEnv.typeUtils
message = processingEnv.messager
filer = processingEnv.filer
message!!.printMessage(Diagnostic.Kind.NOTE,"init 注解处理器初始化")
val s = processingEnv.options["moduleName"]
message!!.printMessage(Diagnostic.Kind.NOTE,"--------->$s")
}
//处理注解
override fun process(p0: MutableSet<out TypeElement>?, p1: RoundEnvironment?): Boolean {
return false
}
}
AbstractProcessor是注解处理器,后续会有一个专门的章节介绍,配合编译的过程。
当一个类被注解修饰之后,AnnotationProcessor需要拿到这个类的信息以便于生成代码,因此需要创建一些能够获取类信息的工具,ProcessingEnvironment中,存在我们想要的工具
public interface ProcessingEnvironment {
Map<String, String> getOptions();
//日志打印
Messager getMessager();
//文件生成
Filer getFiler();
//类 接口 属性的操作,都可以看做一个元素
Elements getElementUtils();
//类信息的操作
Types getTypeUtils();
//获取版本信息
SourceVersion getSourceVersion();
Locale getLocale();
}
在app壳工程中,使用注解,那么在注解处理器中(lay_compiler)怎么拿到app壳工程的参数信息呢,那么在app壳中通过Gradle向注解处理器传递参数
现在是Kotlin的工程,在传参的时候通过kapt — arguments — arg传递参数
kapt {
arguments{
arg("moduleName","zhijiedamamamfamfafafafa")
}
}
AnnotationProcessor # init
override fun init(processingEnv: ProcessingEnvironment?) {
super.init(processingEnv)
elementTool = processingEnv!!.elementUtils
typeTool = processingEnv.typeUtils
message = processingEnv.messager
filer = processingEnv.filer
message!!.printMessage(Diagnostic.Kind.NOTE,"init 注解处理器初始化")
val s = processingEnv.options["moduleName"]
message!!.printMessage(Diagnostic.Kind.NOTE,"--------->$s")
}
通过ProcessingEnvironment获取options,通过key来获取value,将参数从message打印出来
这样,注解处理器的初始化操作就完成,如果app壳中想要使用我们自定义的注解处理器,那么就需要依赖
app壳 # build.gradle
dependencies {
dependency.each { k, v -> implementation v }
if (rootProject.isRelease) {
//依赖包
implementation project(path: ':register')
implementation project(path: ':lay_router')
//kotlin使用kapt依赖 注解处理器,
//Java使用 annotationProcessor
kapt project(path: ':lay_compiler')
}
testImplementation 'junit:junit:4.+'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
}
你以为这样就可以完成了吗,错误❎,这里踩了一个坑,导包依赖之后,无论怎么编译也进不到初始化方法中
当完成注解处理器的初始化操作后,需要在main文件夹下,创建resource — META-INF — services下,创建javax.annotation.processing.Processor文件,其中需要声明我们创建的注解处理器,就相当于注册了
这里这个坑,真的是踩了一下午…