编写android 注解解释器(apt)
步骤:
1. 编写注解文件
2. 写注解解释器,编译时生成注解文件
3. 运行时通过反射调用注解生成的类和方法
编写注解文件
@Retention(RetentionPolicy.CLASS)
@Target(ElementType.TYPE)
public @interface Components {
String[] value();
}
写注解解释器,编译时生成注解文件
@AutoService(Processor.class)
public class RouterProcessor extends AbstractProcessor {
private Filer mFiler
private Messager mMessager
private Map<String, String> mStaticRouterMap = new HashMap<>()
private List<String> mAutoRouterList = new ArrayList<>()
@Override
public synchronized void init(ProcessingEnvironment processingEnvironment) {
super.init(processingEnvironment)
mFiler = processingEnvironment.getFiler()
mMessager = processingEnvironment.getMessager()
}
@Override
public SourceVersion getSupportedSourceVersion() {
return SourceVersion.latestSupported()
}
@Override
public Set<String> getSupportedAnnotationTypes() {
Set<String> set = new HashSet<>()
set.add(AutoRouter.class.getCanonicalName())
set.add(StaticRouter.class.getCanonicalName())
set.add(Component.class.getCanonicalName())
set.add(Components.class.getCanonicalName())
return set
}
@Override
public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
mStaticRouterMap.clear()
mAutoRouterList.clear()
try {
Set<? extends Element> mainAppElement = roundEnvironment.getElementsAnnotatedWith(Components.class)
if (!mainAppElement.isEmpty()) {
processInstaller(mainAppElement)
return true
}
processComponent(roundEnvironment)
} catch (Exception e) {
mMessager.printMessage(Diagnostic.Kind.ERROR, e.getMessage())
}
return true
}
private void processInstaller(Set<? extends Element> mainAppElement) throws IOException {
TypeElement typeElement = (TypeElement) mainAppElement.iterator().next()
JavaFileObject javaFileObject = mFiler.createSourceFile(Config.ROUTER_MANAGER, typeElement)
PrintWriter writer = new PrintWriter(javaFileObject.openWriter())
writer.println("package " + Config.PACKAGE_NAME + ";")
writer.println("public class " + Config.ROUTER_MANAGER + " {")
writer.println("public static void " + Config.ROUTER_MANAGER_METHOD + "() {")
Components componentsAnnotation = typeElement.getAnnotation(Components.class)
String[] components = componentsAnnotation.value()
for (String item : components) {
writer.println(Config.FILE_PREFIX + item + ".router();")
}
writer.println("}")
writer.println("}")
writer.flush()
writer.close()
}
private void processComponent(RoundEnvironment roundEnvironment) throws Exception {
Set<? extends Element> compElements = roundEnvironment.getElementsAnnotatedWith(Component.class)
if (compElements.isEmpty()) { return
Element item = compElements.iterator().next()
String componentName = item.getAnnotation(Component.class).value()
Set<? extends Element> routerElements = roundEnvironment.getElementsAnnotatedWith(StaticRouter.class)
for (Element e : routerElements) {
if (! (e instanceof TypeElement)) { continue
TypeElement typeElement = (TypeElement) e
String pattern = typeElement.getAnnotation(StaticRouter.class).value()
mStaticRouterMap.put(pattern, typeElement.getQualifiedName().toString())
}
Set<? extends Element> autoRouterElements = roundEnvironment.getElementsAnnotatedWith(AutoRouter.class)
for (Element e : autoRouterElements) {
if (!(e instanceof TypeElement)) { continue
TypeElement typeElement = (TypeElement) e
mAutoRouterList.add(typeElement.getQualifiedName().toString())
}
writeComponentFile(componentName)
}
private void writeComponentFile(String componentName) throws Exception {
String className = Config.FILE_PREFIX + componentName
JavaFileObject javaFileObject = mFiler.createSourceFile(className)
// javaFileObject.delete()
PrintWriter printWriter = new PrintWriter(javaFileObject.openWriter())
printWriter.println("package " + Config.PACKAGE_NAME + ";")
printWriter.println("import android.app.Activity;")
printWriter.println("import android.app.Service;")
printWriter.println("import android.content.BroadcastReceiver;")
printWriter.println("public class " + className + " {")
printWriter.println("public static void router() {")
// // Router.router(ActivityRule.ACTIVITY_SCHEME + "shop.main", ShopActivity.class)
for(Map.Entry<String, String> entry : mStaticRouterMap.entrySet()) {
printWriter.println("org.loader.router.Router.router(\"" + entry.getKey()
+"\", "+entry.getValue()+".class);")
}
for (String klass : mAutoRouterList) {
printWriter.println("if (Activity.class.isAssignableFrom(" + klass + ".class)) {")
printWriter.println("org.loader.router.Router.router(org.loader.router.rule.ActivityRule.ACTIVITY_SCHEME + \""
+klass+"\", " + klass + ".class);")
printWriter.println("}")
printWriter.println("else if (Service.class.isAssignableFrom(" + klass + ".class)) {")
printWriter.println("org.loader.router.Router.router(org.loader.router.rule.ServiceRule.SERVICE_SCHEME + \""
+klass+"\", " + klass + ".class);")
printWriter.println("}")
printWriter.println("else if (BroadcastReceiver.class.isAssignableFrom(" + klass + ".class)) {")
printWriter.println("org.loader.router.Router.router(org.loader.router.rule.ReceiverRule.RECEIVER_SCHEME + \""
+klass+"\", "+klass+".class);")
printWriter.println("}")
}
printWriter.println("}")
printWriter.println("}")
printWriter.flush()
printWriter.close()
}
}

使用注解
@Component("bbs")
public class BBS {
}
编译后生成注解类

public class Router_bbs {
public static void router() {
if (Activity.class.isAssignableFrom(org.loader.bbslib.BBSActivity.class)) {
org.loader.router.Router.router(org.loader.router.rule.ActivityRule.ACTIVITY_SCHEME + "org.loader.bbslib.BBSActivity", org.loader.bbslib.BBSActivity.class)
}
else if (Service.class.isAssignableFrom(org.loader.bbslib.BBSActivity.class)) {
org.loader.router.Router.router(org.loader.router.rule.ServiceRule.SERVICE_SCHEME + "org.loader.bbslib.BBSActivity", org.loader.bbslib.BBSActivity.class)
}
else if (BroadcastReceiver.class.isAssignableFrom(org.loader.bbslib.BBSActivity.class)) {
org.loader.router.Router.router(org.loader.router.rule.ReceiverRule.RECEIVER_SCHEME + "org.loader.bbslib.BBSActivity", org.loader.bbslib.BBSActivity.class)
}
}
}
通过反射调用
public class RouterHelper {
public static void install() {
try {
Class<?> klass = Class.forName(Config.PACKAGE_NAME + "." + Config.ROUTER_MANAGER);
Method method = klass.getDeclaredMethod(Config.ROUTER_MANAGER_METHOD);
method.invoke(null);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}