有多简单,仅仅只有跳转功能,主要为了了解AbstractProcessor的使用
是什么
也就是常说的APT,和aapt不一样啊,不一样的东西。
是一个在javac中的,用来编译时扫描和处理的注解的工具。你可以为特定的注解,注册你自己的注解处理器。
干嘛用
比如各种路由框架,黄油刀什么的都会使用到 apt,为什么要用呢,还是为了能够生成代码,有些代码不用使用者去使用,比较方便
怎么用
先说流程,先依赖,然后需要写一个注解,一般都是根据注解来处理,其次继承AbstractProcessor,在process函数中,生成自己需要的类。
依赖
implementation 'com.google.auto.service:auto-service:1.0-rc6'
annotationProcessor 'com.google.auto.service:auto-service:1.0-rc6'
implementation 'com.squareup:javapoet:1.10.0'
compileOnly files(Jvm.current().getToolsJar())
写个注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.CLASS)
public @interface Router {
String path();
}
继承AbstractProcessor
@AutoService(Processor.class)
@SupportedAnnotationTypes("net.mikaelzero.interfaces.Router")
@SupportedSourceVersion(SourceVersion.RELEASE_8)
public class UriProcessor extends BaseProcessor {
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
super.process(annotations, roundEnv);
.......
return true;
}
}
BaseProcessor是啥,直接copy WMRouter的
两个注意点,注解写在单独的module中,比如叫interfaces,处理AbstractProcessor的也写在一个单独的module中,比如叫complie,这两个都是java工程,不是android工程。
生成java文件
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
super.process(annotations, roundEnv);
if (annotations == null || annotations.isEmpty()) {
return false;
}
CodeBlock.Builder builder = CodeBlock.builder();
for (Element element : roundEnv.getElementsAnnotatedWith(Router.class)) {
if (!(element instanceof Symbol.ClassSymbol)) {
continue;
}
boolean isActivity = isActivity(element);
if (!isActivity) {
continue;
}
Symbol.ClassSymbol cls = (Symbol.ClassSymbol) element;
Router uri = cls.getAnnotation(Router.class);
if (uri == null) {
continue;
}
CodeBlock handler = buildHandler(isActivity, cls);
String path = uri.path();
builder.addStatement("handler.register($S, $L)", path, handler);
}
//由于随机生成类名,需要根据接口去找对应实现类,代码量较多,作为演示,取一个固定的名字
buildHandlerInitClass(builder.build(), "UriAnnotationInitImpl", Const.URI_ANNOTATION_HANDLER_CLASS, Const.URI_ANNOTATION_INIT_CLASS);
return true;
}
点击小锤子编译后,看看生成的文件,文件在你使用annotationProcessor compile的module中的generated中
public class UriAnnotationInitImpl implements IUriAnnotationInit {
public void init(UriHandler handler) {
handler.register("/second", "net.mikaelzero.second.SecondActivity");
}
}
IUriAnnotationInit是个啥,虽然我们编写好了生成代码的策略,但是这个生成好的代码,该怎么运行?
没错,用一个接口,在通过开放一个函数(比如init什么的),在init中,对所有实现了该接口的实现类进行实例化并且调用。
最后一步
调用上面的init函数,为了追求简单,我直接在生成类的时候生成为固定的名字,然后实例化并调用init
void init() {
try {
Class<?> clazz = Class.forName("net.mikaelzero.router.generated.UriAnnotationInitImpl");
IUriAnnotationInit annotationInit = (IUriAnnotationInit) clazz.newInstance();
annotationInit.init(new UriHandler());
} catch (ClassNotFoundException | IllegalAccessException | InstantiationException e) {
e.printStackTrace();
}
}
再看看UriHandler
public class UriHandler {
private static final Map<String, String> mMap = new HashMap<>();
public void register(String path, String handler) {
String pathHandler = mMap.get(path);
if (pathHandler == null) {
mMap.put(path, handler);
}
}
public static Intent createIntent(Context context, @NonNull String path) {
return new Intent().setClassName(context, mMap.get(path));
}
}
同样追求简单,直接写成了static,最后就是调用,并跳转了.
@Router(path = "/second")
public class SecondActivity extends AppCompatActivity {
......
}
startActivity(UriHandler.createIntent(this, "/second"));
总结
看起来好像和gradle没啥关系啊,但是gradle和asm有关系,javapoet和asm有关系