简介
Annotations, a form of metadata, provide data about a program that is not part of the program itself. Annotations have no direct effect on the operation of the code they annotate.
注释是元数据的一种形式,为程序的元素(类、方法、变量)提供一些说明,但是不会对程序本身造成影响。
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Test {
String value();
}
直接使用@Test(“demo”),等同于@Test(value=”demo”)
添加默认值:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface TestDefault {
public String description() default "demo";
}
很多使用作为一种辅助途径,应用在软件框架或工具中。这些工具类可以根据不同的Annotation心采取不同的处理,具有”让编译器进行编译检查的功能”
标准的Annotation
从1.5开始就自带三张标准的Annotation类型:
在Android的获取控件中都需要findViewById()来获取,通过注解的来获取到Id的值进行绑定例如:
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ViewInject{
int viewId();
}
注解声明完后,可以定义一些控件来使用:
@ViewInject(viewId = R.id.test)
private TextView test;
运行时Annotation解析
该类是指@Retention为RUNTIME的Annotation。
该类型的解析其实本质的使用反射。反射执行的效率是很低的
如果不是必要,应当尽量减少反射的使用,因为它会大大拖累你应用的执行效率。
例如:
public static void viewInject(Activity activity){
Class extends Activity> obj=activity.getClass();
Field[] fields=obj.getDeclaredFields();//获取声明的字段
for (Field field :fields){
ViewInject viewInject=field.getAnnotation(ViewInject.class);
if(viewInject!=null){
int viewId=viewInject.viewId();
if(viewId!=-1){
try {
Method method=obj.getMethod("findViewById",int.class);
Object view=method.invoke(activity,viewId);
field.setAccessible(true);//设置属性可以访问
field.set(activity,view);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
//声明的保留时期为编译时期
@Retention(CLASS) @Target(FIELD)
public @interface BindView {
/** View ID to which the field will be bound. */
@IdRes int value();
}
使用的是编译类型的注解,这样就不会通过反射来获取数值,不会影响性能。
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.CLASS)
public @interface AnnotationTest {
String value() default "";
}
@SupportedAnnotationTypes("com.example.AnnotationTest")
@SupportedSourceVersion(SourceVersion.RELEASE_7)
public class TestProcessor extends AbstractProcessor {
@Override
public boolean process(Set extends TypeElement> annotations, RoundEnvironment roundEnv) {
System.out.println("process");
for (TypeElement te : annotations) {
for (Element element : roundEnv.getElementsAnnotatedWith(te)) {
AnnotationTest annotation = element.getAnnotation(AnnotationTest.class);
String value = annotation.value();
System.out.println("type : " + value);
}
}
return true;
}
}
注意:@SupportedAnnotationTypes(“com.charon.AnnotationTest”)来指定要处理的注解类。
@SupportedSourceVersion(SourceVersion.RELEASE_7)指定编译的版本。这种通过注解指定编译版本和类型的方式是从Java 1.7才有的。
对于之前的版本都是通过重写AbstractProcessor中的方法来指定的。
- 注册处理器
我们自定义了Processor那如何才能让其生效呢?就是在annotations的java同级目录新建resources/META-INF/services/javax.annotation.processing.Processor文件
然后在javax.annotation.processing.Processor文件中指定自定义的处理器,如:
com.example.TestProcessor
- 在app中进行使用
进行Build会在控制台看到输出的信息。
As of the Android Gradle plugin version 2.2, all functionality that was previously provided by android-apt is now available in the Android plugin. This means that android-apt is officially obsolete
Here are the steps to migrate:
Make sure you are on the Android Gradle 2.2 plugin or newer.
Remove the android-apt plugin from your build scripts
Change all apt, androidTestApt and testApt dependencies to their new format:
dependencies {
compile 'com.google.dagger:dagger:2.0'
annotationProcessor 'com.google.dagger:dagger-compiler:2.0'
}
在自定义注解时,一般来说可能会建三个modules:
dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
//Google Auto的主要作用是注解Processor类,并对其生成META-INF的配置信息,
//可以让你不用去写META-INF这些配置文件,只要在自定义的Processor上面加上@AutoService(Processor.class)
compile 'com.google.auto.service:auto-service:1.0-rc2'
//可以更方便的生成代码,它可以帮助我们通过类调用的形式来生成代码。
compile 'com.squareup:javapoet:1.7.0'
compile project(':apimodule')
}
compile project(':compilermodule')
annotationProcessor project(':compilermodule')
@Retention(RetentionPolicy.CLASS)
@Target(ElementType.TYPE)
public @interface Factory {
String id();
Class type();
}
@AutoService(Processor.class)
public class MyProcessor extends AbstractProcessor {
//初始化操作的方法,RoundEnvironment会提供很多有用的工具类Elements、Types和Filer等。
@Override
public synchronized void init(ProcessingEnvironment processingEnv) {
super.init(processingEnv);
}
//这相当于每个处理器的主函数main()。在该方法中去扫描、评估、处理以及生成Java文件。
@Override
public boolean process(Set extends TypeElement> annotations, RoundEnvironment roundEnv) {
System.out.println("Hello Wolrd,Custom Processor");
return false;
}
//这里你必须指定,该注解器是注册给哪个注解的
@Override
public Set getSupportedAnnotationTypes() {
return super.getSupportedAnnotationTypes();
}
//用来指定你使用的java版本。通常这里会直接放回SourceVersion.latestSupported()
@Override
public SourceVersion getSupportedSourceVersion() {
return SourceVersion.latestSupported();
}
}
从jdk 1.7开始,可以使用如下注解来代替getSupporedAnnotationTypes()和getSupportedSourceVersion()方法:
@SupportedSourceVersion(SourceVersion.latestSupported())
@SupportedAnnotationTypes({
// 合法注解全名的集合
})
非常感谢分析。
参考链接:http://blog.csdn.net/charon_chui/article/details/51896830
实践例子
Hannes Dorfmann