Annotation(注解)就是Java提供了一种元程序中的元素关联任何信息和着任何元数据(metadata)的途径和方法。Annotion(注解)是一个接口,程序可以通过反射来获取指定程序元素的 Annotion对象,然后通过 Annotion对象 来获取注解里面的元数据。
Annotation(注解)是JDK5.0及以后版本引入的。它可以用于创建文档,跟踪代码中的依赖性,甚至执行基本编译时检查。从某些方面看,annotation 就像修饰符一样被使用,并应用于包、类 型、构造方法、方法、成员变量、参数、本地变量的声明中。这些信息被存储在 Annotation 的 “name=value” 结构对中。
可能大多数对于这一类框架,都只是停留在用的阶段,但是作为一个程序员,我们有必要去了解它是如何实现的。其实它的原理也没有多复杂,用到了java中反射和注解的相关知识,所以对反射和注解了解不多的朋友可以先找一下相关资料了解一下。
关于注解,我推荐一篇文章(简单易懂)http://mp.weixin.qq.com/s/NwlIy_knmx4Es7kFnk0gRQ
今天的任务呢就是教大家如何一步一步简单的实现一个类似 ButterKnife的依赖注入的效果:
第一步:我们需要自定义注解,如下:
//对于初始化view和绑定点击事件是不一样的
首先是初始化view
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface BindView {
int value() default 0;
}
绑定点击事件
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface BindClick {
int function() default 0;
}
从上面的Target里面的值我们可以知道,这两个注解一个是作用于属性,一个是作用于方法的.这里提醒一下
,如果只有一个参数成员,最好把参数名称设为value,这里可以补一句因为使用该注解时,value作为key可省略,在使用的时候比较方便。
RetentionPolicy是在什么时刻起作用,比如:编码时,编译时,运行时.我们一般常用的是运行时.
第二步:对获取到的注解,进行处理
public class InjectUtils {
public static void inject(final Activity activity){
Class<Activity> activityClass= (Class<Activity>) activity.getClass();
//遍历属性,对设置注解的view进行初始化
final Field[] fields = activityClass.getDeclaredFields();
for (Field field : fields) {
//判断遍历的属性中是否存在BindView这种类型
if(field.isAnnotationPresent(BindView.class)){
//获取绑定事件中的参数名称
final int viewId = field.getAnnotation(BindView.class).value();
final View viewById = activity.findViewById(viewId);
try {
//这一行代码是必须的,否则直接调用set方法不生效
field.setAccessible(true);
field.set(activity,viewById);
} catch (Exception e) {
e.printStackTrace();
}
}
}
//遍历方法 将设置注解的方法绑定到相应的view的点击事件中
final Method[] methods = activityClass.getDeclaredMethods();
for (final Method method : methods) {
final BindClick annotation = method.getAnnotation(BindClick.class);
if(annotation!=null){
final int function = annotation.function();
activity.findViewById(function).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//调用该方法
method.setAccessible(true);
try {
method.invoke(activity);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
}
}
}
第三步:设置注解
@BindView(R.id.tv) TextView tv;
tv.setText("====妖精还我爷爷==");
@BindClick(function = R.id.tv) public void dj(){ Toast.makeText(this,"我是你爷爷",Toast.LENGTH_SHORT).show(); }
第四步:只需要调用一下
setContentView(R.layout.activity_main); //必须放在setContentView后面 InjectUtils.inject(this);
然后就达到了我们想要的效果,请多指教