注解(Annotation),也叫元数据。一种代码级别的说明。它是JDK1.5及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。
基础知识
相信大家在Android开发过程中,对注解有一定程度的接触,比如我们在使用EventBus的时候,我们声明
@Subscribe(threadMode = ThreadMode.MainThread)
来接受通过EventBus发出来的数据,
还有ButterKnife,我们在使用OnClick添加点击事件或Bind绑定组件的时候,同样也有类似的写法
@Bind(R.id.index_image)
@OnClick({R.id.index_layout)
以至于什么@Override、@Deprecated、@SuppressWarnings这就不需要说了。
我们在写的时候,最大的感触就是:太方便了!!!直接加一个声明就Ok了。你是不是心动了,自己也写几个注解,是不是程序能够更加简洁一些了?先别急,看看注解的结构
@Retention(CLASS)
@Target(FIELD)
public @interface Bind {
/** View ID to which the field will be bound. */
int[] value();
}
其实一点概念都不知道的话,确实看到这个会懵逼。我们一个个来解释一下
-
Retention 表示在什么级别保留此信息
SOURCE:源码注解,注解仅存在代码中,注解会被编译器丢弃
CLASS:编译时注解,注解会在class文件中保留,但会被VM丢弃
RUNTIME:运行时注解,VM运行期间也会保留该注解,因此可以通过反射来获得该注解 -
Target 表示作用域,可能的ElementType参数包括:
CONSTRUCTOR:构造方法声明
FIELD:字段声明
LOCAL_VARIABLE:局部变量声明
METHOD:方法声明
PACKAGE:包声明
PARAMETER:参数声明
TYPE:类,接口或enum声明 - Inherited 容许子类继承
- Documented 生成javadoc时会包含注解
实战1---获取注解值
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface MyAnnotation {
String value() default "defaultValue";
int age();
}
我们声明了一个运行时的注解,可以作用在类还有方法上,包含2个成员变量,其中value有一个默认值是defaultValue
来看看如何获取
@MyAnnotation(age = 10)
public class AnnotationDemo {
@MyAnnotation(value = "Hello", age = 100)
public static void main(String[] args) {
try {
Class class_=Class.forName("com.renyu.demo.AnnotationDemo");
Annotation myAnnotation=class_.getAnnotation(MyAnnotation.class);
if (myAnnotation !=null && myAnnotation instanceof MyAnnotation) {
System.out.println(((MyAnnotation) myAnnotation).value()+((MyAnnotation) myAnnotation).age());
}
for (Method method : class_.getDeclaredMethods()) {
MyAnnotation methodAnnotation=method.getAnnotation(MyAnnotation.class);
if (methodAnnotation!=null) {
System.out.println(methodAnnotation.value()+methodAnnotation.age());
}
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
果断打印出期望值
defaultValue10
Hello100
实战2---教你写一个简单的类似ButterKnife工具
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface onClick {
int[] value();
}
这边如出一辙
下面是简单的调度类,负责实际意义上的点击事件处理
public class InjectorProcessor {
public void process(final Object object) {
Class class_=object.getClass();
Method[] methods=class_.getDeclaredMethods();
for (final Method method : methods) {
onClick clickMethod=method.getAnnotation(onClick.class);
if (clickMethod!=null) {
if (object instanceof Activity) {
for (int id : clickMethod.value()) {
View view=((Activity) object).findViewById(id);
view.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
try {
method.invoke(object);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
});
}
}
}
}
}
}
最后使用就很简单了
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
InjectorProcessor processor=new InjectorProcessor();
processor.process(MainActivity.this);
}
@onClick({R.id.textview})
public void click() {
Toast.makeText(this, "HHH", Toast.LENGTH_SHORT).show();
}
}
网友评论