安卓开发中会有很多地方使用到注解,有些是Java中的,有些是三方框架所带的。
Java中的常见的几种标准注解
@Override 表示当前的方法定义将覆盖父类中的方法。
@Deprecated 表示废弃的意思,使用了该注解的方法或者对象,则会有提示。
@SuppressWarnings 关闭不当的编译器警告信息
上述几种标准注解我们在安卓开发的过程中经常会看到,不过我们平常使用的注解还有一类并不是Java提供给我们的,而是我们自定义的。自定义注解需要使用到Java提供的几个元注解。元注解是用在注解上的注解。
Java提供给我们的几个元注解
@Documented 表示是否将注解信息添加在java文档中
@Retention 定义该注解的生命周期
@Target 表示该注解用于什么地方
@Inherited 定义该注释和子类的关系
下面着重解释后三个
-
@Retention
这个元注解表示他所修饰的注解的生命周期,即需要在什么级别保存该注解信息, Retention有一个属性value,是RetentionPolicy类型的,RetentionPolicy是一个枚举 类型,这个枚举决定了Retention注解应该如何去保持。RetentionPolicy有以下三个值 **RetentionPolicy.SOURCE**:注解只保留在源文件,当Java文件编译成class文件的时候,注解被遗弃; **RetentionPolicy.CLASS**:注解被保留到class文件,但jvm加载class文件的时候被遗弃,这是默认的生命周期; **RetentionPolicy.RUNTIME**:注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在;
-
@Target
Target注解说明了他修饰的注解修饰的对象范围,使用的时候类似于
@Target({ElementType.METHOD})
ElementType的取值以及含义如下图
@Inherited
在注解上使用@Inherited 表示该注解会被子类继承,注意,仅针对类,成员属性、方法并不受此注释的影响。
自定义注解的例子:其中的@interface含义为声明新的枚举注解类型
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface DemoAnnotions{
}
安卓中提供的几个元注解
安卓在19.1版本开始引入了一个新的注解库,也包含一些元注解供我们使用。
比如@IntDef & @StringDef,安卓中用@IntDef & @StringDef来代替枚举的使用。
在日常开发中我们时常会有机会写到枚举,但是枚举是很耗内存的。每一个枚举值都是一个单例对象,在使用它时会增加额外的内存消耗。
看一个@IntDef替代枚举的例子:
@IntDef({DemoType.UGC, DemoType.PGC, DemoType.VIDEO, DemoType.IMAGE_TEXT, DemoType.PLAIN_TEXT})
@Retention(RetentionPolicy.SOURCE)
public @interface DemoType {
int UGC = 0;
int PGC = 1;
int VIDEO = 2;
int IMAGE_TEXT = 3;
int PLAIN_TEXT = 4;
}
定义@IntDef有两种方式:
@IntDef({DemoType.UGC, DemoType.PGC, DemoType.VIDEO, DemoType.IMAGE_TEXT, DemoType.PLAIN_TEXT})
@IntDef(flag = true ,value = {DemoType.UGC, DemoType.PGC, DemoType.VIDEO, DemoType.IMAGE_TEXT, DemoType.PLAIN_TEXT})
在安卓中注解肯定不是只有替代枚举这一个作用,事实上我们可以用注解实现非常多的功能。比如我们常用的ButtterKnife中就有很多各种功能的注解。让注解实现一个特定的功能就要说到反射了。
反射
-
反射的定义
Java反射机制是指在运行状态中,对于任意一个类,都能知道这个类的所有属性和方法。对于任何一个对象,都能够调用它的任何一个方法和属性。这样动态获取新的以及动态调用对象方法的功能就叫做反射。在Java中的反射机制,被称为Reflection。它允许运行中的Java程序对自身进行检查,并能直接操作程序的内部属性或方法。Reflection机制允许程序在正在执行的过程中,利用Reflection APIs取得任何已知名称的类的内部信息,包括:package、 type parameters、 superclass、 implemented interfaces、 inner classes、 outer classes、 fields、 constructors、 methods、 modifiers等,并可以在执行的过程中,动态生成Instances、变更fields内容或唤起methods。
-
安卓中反射作用于注解
这里我们实现一个小功能来说明反射怎么作用于注解。
我们首先确定目标,我们实现一个类似于ButterKnife中绑定view的功能,即使用注解代替findViewById的功能。第一步先定义注解:
@Target(ElementType.FIELD) @Retention(RetentionPolicy.CLASS) public @interface MyBindView { int value(); }
第二步写注解解释器
public void injects(AppCompatActivity activity) {
Class<? extends AppCompatActivity> clazz = activity.getClass();
Field[] fields = clazz.getFields();
if (fields != null && fields.length > 0) {
for (Field field : fields) {
//判断字段是否标注MyBindView
MyBindView myBindView = field.getAnnotation(MyBindView.class);
if (myBindView != null) {
//反射访问私有成员,必须加上这句
View view = activity.findViewById(myBindView.value());
if (view != null) {
try {
field.setAccessible(true);
field.set(activity, view);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
}
}
使用的时候如下:
injects(this);
@MyBindView(R.id.account_feedback_btn)
View feedbackBtn;
这样就类似ButterKnife的@bindView功能了。