运行时注解
运行时注解使用 RetentionPolicy.RUNTIME 修饰,注解会被编译器记录在java和class文件中并被虚拟机保留到运行时,可以通过反射处理。由于使用 RetentionPolicy.RUNTIME 修饰代码发生在运行阶段使用反射,所以性能上有所损耗。
一、获取注解
/*
* 获取特定注解
*/
public <T extends Annotation> T getAnnotation(Class<T> annotationClass);
/*
* 指定注解是否存在该元素上
*/
public boolean isAnnotationPresent(Class<? extends Annotation> annotationType);
/*
* 返回类中所有指定注解
* 分别表示获取所有指定的public元素,包括继承的公有方法 和 获取所有本类中的所有指定元素
*/
xxx[] annotations = clazz.getxxxs();
xxx[] annotations = clazz.getDeclaredxxxs();
eg:
/**
* 获取类
*/
public static void parseTypeAnnotation() {
Class clazz = UserAnnotation.class;
Annotation[] annotations = clazz.getAnnotations();
for (Annotation a : annotations) {
MethodInfo annotation = (MethodInfo) a;
MLog.log("class = " + clazz.getName() + " | id = "
+ annotation.id() + " | name = " + annotation.name());
}
}
/**
* 获取构造方法
*/
public static void parseConstructAnnotation() {
Constructor[] constructors = UserAnnotation.class.getDeclaredConstructors();
for (Constructor constructor : constructors) {
boolean hasAnnotation = constructor.isAnnotationPresent(MethodInfo.class);
if (hasAnnotation) {
MethodInfo annotation = (MethodInfo) constructor.getAnnotation(MethodInfo.class);
MLog.log("constructor = " + constructor.getName() + " | id = "
+ annotation.id() + " | name = " + annotation.name());
}
}
}
/**
* 获取方法
*/
public static void parseMethodAnnotation() {
Method[] methods = UserAnnotation.class.getDeclaredMethods();
for (Method method : methods) {
boolean hasAnnotation = method.isAnnotationPresent(MethodInfo.class);
if (hasAnnotation) {
MethodInfo annotation = method.getAnnotation(MethodInfo.class);
MLog.log("method = " + method.getName() + " | id = "
+ annotation.id() + " | name = " + annotation.name());
}
}
}
/**
* 获取属性
*/
public static void parseFieldAnnotation() {
Field[] fields = UserAnnotation.class.getDeclaredFields();
for (Field field : fields) {
boolean hasAnnotation = field.isAnnotationPresent(MethodInfo.class);
if (hasAnnotation) {
MethodInfo annotation = field.getAnnotation(MethodInfo.class);
MLog.log("field = " + field.getName() + " | id = "
+ annotation.id() + " | name = " + annotation.name());
}
}
}
二、使用运行时注解实现简单的findViewById功能
- 自定义注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface IdInject {
int value();
}
- 解析注解,都是反射的知识了
public static void inject(Activity activity) {
Class cls = activity.getClass();
Field[] fields = cls.getDeclaredFields(); // 能获取自己声明的各种字段,包括public,protected,private
if (fields != null) {
for (Field field : fields) {
boolean hasAnnotation = field.isAnnotationPresent(IdInject.class);
if (hasAnnotation) {
IdInject inject = field.getAnnotation(IdInject.class);
View view = activity.findViewById(inject.value());
if (view != null) {
field.setAccessible(true); //能获取自己声明的各种字段,包括public,protected,private
try {
field.set(activity, view);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
}
}
- 使用
在属性声明处添加注解,括号中为TextView中的id
@IdInject(R.id.text)
private TextView text; // 通过反射,故可以用private修饰
在使用前调用下面方法,动态为属性赋值
IdInjectProcessor.inject(this);
这样 text 就已经可以使用了,不用再写 findViewById 了。但是因为是运行时注解,性能不好,不建议使用运行时注解实现 findViewById 功能,可以看后面文章使用编译时注解。