Android自定义注解
注解是一种元数据, 可以添加到java代码中. 类、方法、变量、参数、包都可以被注解,注解对注解的代码没有直接影响。
首先,需要知道的是,注解其实就是一个标注而已,然后后期通过这个标注拿到对应的函数,变量,然后做一些操作(通常是反射)。
定义一个注解用关键字:@interface
如图:
其中:
@Retention(RetentionPolicy.RUNTIME) 表示注解可在运行时可用
@Target(ElementType.FIELD) 表示该注解用于描述变量
BindView注解的名称
int value() default 0; 注解参数的类型,默认为0
上面的注解可以这样使用:
元注解共有四种@Retention, @Target, @Inherited, @Documented
@Retention
说明了注解的可用范围
1.SOURCE, 只在源码中可用
2.CLASS, 在源码和字节码中可用
3.RUNTIME, 在源码,字节码,运行时均可用
@Target
说明了注解所修饰的对象范围:注解可被用于 packages、types(类、接口、枚举、Annotation类型)、类型成员(方法、构造方法、成员变量、枚举值)、方法参数和本地变量(如循环变量、catch参数)。在注解类型的声明中使用了target可更加明晰其修饰的目标。
作用:用于描述注解的使用范围(即:被描述的注解可以用在什么地方)
取值(ElementType)有:
1.CONSTRUCTOR:用于描述构造器
2.FIELD:用于描述域(变量)
3.LOCAL_VARIABLE:用于描述局部变量
4.METHOD:用于描述方法(函数)
5.PACKAGE:用于描述包
6.PARAMETER:用于描述参数
7.TYPE:用于描述类、接口(包括注解类型) 或enum声明
@Documented
用于描述其它类型的annotation应该被作为被标注的程序成员的公共API,因此可以被例如javadoc此类的工具文档化。Documented是一个标记注解,没有成员。
@Inherited
元注解是一个标记注解,@Inherited阐述了某个被标注的类型是被继承的。如果一个使用了@Inherited修饰的注解类型被用于一个class,则这个注解将被用于该class的子类。
注意:@Inherited 类型是被标注过的class的子类所继承。类并不从它所实现的接口继承注解,方法并不从它所重载的方法继承注解。
当@Inherited类型标注的注解的Retention是RetentionPolicy.RUNTIME,则反射API增强了这种继承性。如果我们使用java.lang.reflect去查询一个@Inherited 类型的注解时,反射代码检查将展开工作:检查class和其父类,直到发现指定的注解类型被发现,或者到达类继承结构的顶层。
其中, @Retention是定义保留策略, 直接决定了我们用何种方式解析. SOUCE级别的注解是用来标记的, 比如Override, SuppressWarnings. 我们真正使用的类型是CLASS(编译时)和RUNTIME(运行时)
定义注解:
举个例子:
定义一个BindView注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface BindView {
int value() default 0;
}
使用BindView注解(在变量前面添加)
@BindView(R.id.tv)//把id存到注解里
private TextView tv;
这时有人就要问了:这样就能绑定一个View了?在逗我吗?
先别急,还没讲完呢。。。
这样当然不能直接绑定一个View,还需要写代码通过反射的方式去给变量赋值
直接上代码:
@BindView(R.id.tv)//把id存到注解里
private TextView tv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
bind(this);//重要,调用此方法赋值变量
}
public void bind(final Activity activity){
try {
Class clazz = activity.getClass();
Field[] fields = clazz.getDeclaredFields();//获取所有的变量
for (Field field : fields){//遍历所有的变量
if (field.isAnnotationPresent(BindView.class)){ //判断当前变量是否有BindView注解
BindView bindView = field.getAnnotation(BindView.class); //获取当前变量的BindView注解
int id = bindView.value();//把注解里的值取出来(就是上面的R.id.tv)
if (id != 0){
field.setAccessible(true);//暴力反射
field.set(activity,activity.findViewById(id));//通过反射的方式赋值变量
}
}
}
}catch (Exception e){
e.printStackTrace();
}
}
上面的代码就是通过注解完成了一个绑定View的操作。
基本的自定义注解大概就是这样,剩下的可以把bind方法做一下封装。
可以封装BindView,BindOnClick,BindIntent,BindLayout等等,大家自由发挥。
文章到这就结束了。
本文参考了这篇文章:Android进阶之自定义注解