前言
注解,也被称为元数据
,为我们在代码中添加信息提供了一种形式化的方法,使我们可以在稍后某个时刻非常方便地使用这些数据。
很多文章都是讲述java注解的,而且很多例子虽然有和Android互通的部分,但是Android开发中也扩展了很多单纯Java中没有的注解应用。所以这里主要介绍Android开发中的注解,当然包括Java注解。
Java注解
Java 注解(Annotation
)又称 Java 标注,是 JDK5.0 引入的一种注释机制。 Java 语言中的类、方法、变量、参数和包等都可以被标注。和 Javadoc 不同,Java 标注可以通过反射获取标注内容。在编译器生成类文件时,标注可以被嵌入到字节码中。Java 虚拟机可以保留标注内容,在运行时可以获取到标注内容 。 当然它也支持自定义 Java 标注。
Java内置了三种标准注解,其定义在java.lang中。
-
@Override
,表示当前的方法定义将覆盖超类中的方法。 -
@Deprecated
,被此注解标记的元素表示被废弃,如果程序员使用了注解为它的元素,那么编译器会发出警告。 -
@SuppressWarnings
,关闭不当的编译器警告信息。
这几种注解我们平时开发中肯定经常用到,但是你可能很少看到注解原来的样子。如下为注解的类,可以看到,除了@符号的使用以外,它基本与Java固有语法一致。只是注解上又增加了其他注解。
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE})
public @interface Deprecated {
}
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.SOURCE)
public @interface SuppressWarnings {
String[] value();
}
那注解上的注解又是啥呢,这里就要引出接下来要说的,元注解,专职负责注解其他的注解。
经过对元注解的表格进行理解,可以回头看我们平常使用的标准注解Override
、Deprecated
和SuppressWarnings
。可以看到他们分别都由元注解进行了注释,并且我们能够明白,为啥@Override
只能用在方法上,而不能用在类、构造函数、变量上,而@Deprecated
就可以用在构造函数、变量、方法、包、参数等,因为其代表的意义就可以表示它能够标注的所有类型都是废弃的元素。
另外,我们需要对Java程序或者Android程序的三个阶段进行解释。
RetentionPolicy.SOURCE
注解只在源码阶段保留,在编译器进行编译时它将被丢弃忽视。RetentionPolicy.CLASS
注解只被保留到编译进行的时候,它并不会被加载到 JVM 中。RetentionPolicy.RUNTIME
注解可以保留到程序运行的时候,它会被加载进入到 JVM 中,所以在程序运行时可以获取到它们。
Android注解
本来在Android系统源码中/frameworks/base/core/java/android/annotation中是有很多的注解的,但是呢,他们都是系统源码用的注解,不是给我们这种开发人员用的,因为所有的注解的注释上都有@hide
注释。
* {@hide}
*/
@Documented
@Retention(SOURCE)
@Target({METHOD, PARAMETER, FIELD})
public @interface AnyRes {
}
Android系统给我们提供的SDK中,只有两个原生注解:
@TargetApi
使高版本API的代码在低版本SDK不报错
@SuppressLint
使用此标注让Lint忽略指定的警告
使用注解的框架
-
JUnit
是一个Java语言的单元测试框架,可以大大缩短你的测试时间和准确度。
-
ButterKnife
Android 开发中 IOC 框架,它减少了大量重复的代码。专注于Android系统的View注入框架,以前总是要写很多findViewById来找到View对象,有了ButterKnife可以很轻松的省去这些步骤。并且使用ButterKnife对性能基本没有损失,因为ButterKnife用到的注解并不是在运行时反射的,而是在编译的时候生成新的class文件。
-
Retrofit
Retrofit 是一个 RESTful 的 HTTP 网络请求框架的封装,网络请求的工作本质上是 OkHttp 完成,而 Retrofit 仅负责 网络请求接口的封装。Retrofit通过注解的方式,进行网络请求描述。
-
EventBus
EventBus是一种用于Android的事件发布-订阅总线,由GreenRobot开发,它简化了应用程序内各个组件之间进行通信的复杂度,尤其是碎片之间进行通信的问题,可以避免由于使用广播通信而带来的诸多不便。
自定义注解
自定义注解InjectDIYLayout
, 这里为了简单示例用了运行时注解,并采用反射方法调用执行。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface InjectDIYLayout {
int value();
}
实现工具类,在BaseActivity中的onCreate中初始化。InjectDIYUtils .inject(this);
public class InjectDIYUtils {
private static final String TAG = "InjectDIYUtils";
public static void inject(Object context){
injectDIYLayout (context);
}
}
通过类getAnnotation得到此类注释的注解,经打印可以判断是否此注解。然后通过反射获取到setContentView,并用反射方法的invoke调用,传入注解中的layout值。
private static void injectDIYLayout (Object context) {
Class<?> aClass = context.getClass();
InjectDIYLayout annotation = aClass.getAnnotation(InjectDIYLayout.class);
Log.e(TAG, "injectLayout: annotation.value()="+annotation.value());
try {
Method contentView = aClass.getMethod("setContentView", int.class);
try {
Object invoke = contentView.invoke(context, annotation.value());
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
使用举例:
@InjectDIYLayout(R.layout.activity_main)
public class MainActivity extends BaseActivity {
网友评论