Android自定义注解

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进阶之自定义注解

猜你喜欢

转载自blog.csdn.net/Jamingx666/article/details/82530363