前言
相对于上一节的编译时注解,运行时注解的书写要简单很多,基本思路就是写一个注解标记,通过getAnnotation拿到该类的注解标签做一些我们想要做的事情。
一:注解标签@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.TYPE})
public @interface BindId {
int value() default View.NO_ID;
}
上面就是我们用来给view或者id进行注解的自定义注解类,以@开头,加interface修饰,跟接口的唯一区别就是多了个@。下面我们要写具体的api来实现它的绑定功能:
二:检测类中的标签,来做一些需要的事情例如本例的,检测到BindID.class的话,我们就知道需要调用setContentView、findViewById来处理该标签。
public class BindIdApi {
public static void bindId(Activity obj) {
Class cls = obj.getClass();
//获取当前Activity的所有方法,包括私有
Method methods[] = cls.getDeclaredMethods();
for (int i = 0; i < methods.length; i++) {
final Method method = methods[i];
if (method.isAnnotationPresent(BindOnClick.class)) {
// 得到这个类的OnClick注解
BindOnClick mOnClick = (BindOnClick) method.getAnnotation(BindOnClick.class);
// 得到注解的值
int[] id = mOnClick.value();
for (int j = 0; j < id.length; j++) {
final View view = obj.findViewById(id[j]);
view.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//反射指定的点击方法
try {
//私有方法需要设置true才能访问
method.setAccessible(true);
method.invoke(obj, view);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
});
}
}
}
}
}
基本上注释里面都写的很清楚了。也是首先找到这个view,然后调用setOnClickListener去设置点击事件,再反射调用注解的方法,最终去执行点击事件。最后在Activity的onCreate中绑定该事件:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
BindIdApi.bindId2(this);
BindOnClick.bindOnClick(this);
tv.setText("通过注解ID,运行时注解查找");
}
@OnClick(R.id.tv)
private void click(View view){
switch (view.getId()){
case R.id.tv:
Toast.makeText(this,"annotation",Toast.LENGTH_LONG).show();
break;
}
}
项目代码:
https://github.com/buder-cp/base_component_learn/tree/master/annotation_learn
注解相关的较好的文章:
https://mp.weixin.qq.com/s/cZf87Du11cqWD0GF2PmPyw
https://mp.weixin.qq.com/s/ljJ1uBCinBLhCU6MtOApYA
https://mp.weixin.qq.com/s/fJKAwpqn_hXRXRS4oh1dEw
https://mp.weixin.qq.com/s/cjGADwzfb3hWtfYvm0J2LQ