Android注解详解

一、什么是注解?

注解是一种元数据, 可以添加到java代码中。类、方法、变量、参数、包都可以被注解,注解对注解的代码没有直接影响。注解并没有什么魔法, 之所以产生作用, 是解析注解后做了相应的处理。注解仅仅只是个标记罢了。

例如@Override就是注解,它的作用是:

1、检查是否正确的重写了父类中的方法。

2、标明代码,这是一个重写的方法。

注解使用@interface定义,@Override的定义如下:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}

二、元注解

1、设么是元注解

Java内置的注解有Override, Deprecated, SuppressWarnings等, 作用相信大家都知道。

Override注解的源码如下:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}

Override注解上面有两个注解, 这就是元注解。元注解是用来定义注解的注解,其作用是定义注解的作用范围, 使用在什么元素上等, 下面来详细介绍。

2、元注解分类

元注解共有四种@Retention、@Target、 @Inherited,、@Documented。

1)、@Retention

保留的生命周期,取值为RetentionPolicy的枚举,默认值为CLASS.。可选值有三种

SOURCE: 只在源码中有效,编译时抛弃,如上面的@Override

CLASS: 编译class文件时生效(编译时注解)

RUNTIME: 运行时才生效(运行时注解)

2)、@Target

可以用来修饰哪些程序元素,取值为ElementType枚举。未标注则表示可修饰所有。

TYPE:类、接口、枚举、注解类型。

FIELD:类成员(构造方法、方法、成员变量)。

METHOD:方法。

PARAMETER:参数。

CONSTRUCTOR:构造器。

LOCAL_VARIABLE:局部变量。

ANNOTATION_TYPE:注解。

PACKAGE:包声明。

TYPE_PARAMETER:类型参数。

TYPE_USE:类型使用声明。

3)、@Inherited

注解自定义的注解。在继承时默认无法继承父类的注解,除非注解声明了 @Inherited

4)、@Documented

是否会保存到 Javadoc 文档中

三、自定义注解基础

1、定义注解

定义新的注解使用@interface关键字,定义注解和定义接口方式很像,通用格式如下:

public @interface 注解名 {
    方法参数
}

定义一个简单的注解如下:

public @interface Testable {
}

定义了注解后,可以在程序任意位置使用该注解。通常可用于修饰程序中的类、方法、变量、接口等。一般会把注解放在所有修饰符前面,并且注解可能需要为成员变量指定值,注解的长度可能较长,所以通常把注解单独放一行。如下:

@Testable
public class MyTest {
}

2、为注解添加成员变量

注解还可以带成员变量,成员变量以无形参的方法形式来声明。方法的返回值类型定义成员变量的类型,方法名定义成员变量的名字。使用default关键字指定成员变量的默认值。成员变量定义如下:

public @interface GetViewTo {
    int value() default -1;
}

value就是成员变量,默认值时-1

使用注解GetViewTo:

@GetViewTo(R.id.btn_one)
Button btnOne;

注意变量名是value使用时可以在括号中直接填入变量值即可。如果变量名是其他的,就需要指定变量名。

定义注解User

public @interface User {
    String name();
    int age();
}

使用注解User

@User(name = "小王", age = 18)
String user;

name和age的先后顺序可以互换,但是必须指定变量名name和age

四、自定义注解

1、自定义运行时注解

该注解的作用是在运行时获取控件实例。

1)、定义注解

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface GetViewTo {
    int value() default -1;
}

指定注解的的对象的类成员,该注解在运行时有效。注解中有一个成员变量value,用于保存控件的id。

2)、使用注解

    @GetViewTo(R.id.btn_one)
    Button btnOne;

但是这样并不能实现获取控件id的功能,定义注解主要的工作时如何通过注解实现想要的功能,一般通过反射实现。

3)、在运行时通过反射获取控件的id

private void getAllAnnotationView() {
    //获得成员变量
    Field[] fields = this.getClass().getDeclaredFields();

    for (Field field : fields) {
        try {
            //判断该成员是否有注解
            if (field.getAnnotations() != null) {
                //确定注解类型
                if (field.isAnnotationPresent(GetViewTo.class)) {
                    //允许修改反射属性
                    field.setAccessible(true);
                    GetViewTo getViewTo = field.getAnnotation(GetViewTo.class);
                    //findViewById将注解的id,找到View注入成员变量中
                    field.set(this, findViewById(getViewTo.value()));
                }
            }
        } catch (Exception e) {
        }
    }
}

2、自定义编译时注解

运行时注解一般要使用反射,反射的效率比较低,为了提供效率我们可以使用编译时注解。

编译时注解要使用注解处理器AbstractProcessor。一般第三方注解相关的类库,如BufferKnike、ARouter都有一个Compiler命名的Module,这里面一般都是注解处理器,用于编译时处理对应的注解。

注解处理器(Annotation Processor)是Javac的一个工具,它用来在编译时扫描和处理注解。你可以自定义注解,并注册相应的注解处理器,用于处理你的注解逻辑。

下图就是ButterKnife中源码项目结构图,箭头指向的Module就是定义注解处理器的。

具体如何自定义编译器注解见博客Android使用注解处理器实现ButterKnife

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值