自定义注解实现findViewById、onClick

findViewById注解

实现效果:

只要在需要注解的Activity中声明开启,就能够对字段绑定注解:像这样:

@BindView(R.id.recycler)
private RecyclerView recyclerView;

@BindView(R.id.rg)
private RadioGroup radioGroup;

@BindView(R.id.tv)
private RadioGroup textView;

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(getLayoutId());
    MyTool.init(this);
}

开始实现:

1、定义一个注解接口,然后在它上面声明该注解用于字段,并且在程序编译时保留该注解:

@Target({ElementType.FIELD}) //声明该注解用于字段
@Retention(RetentionPolicy.RUNTIME)  //跑起来时用
public @interface BindView{
    int value(); //注解传入的参数为int类型
}

 说明一下:

@Retention:注解的保留位置         

@Retention(RetentionPolicy.SOURCE)   //注解仅存在于源码中,在class字节码文件中不包含

@Retention(RetentionPolicy.CLASS)     // 默认的保留策略,注解会在class字节码文件中存在,但运行时无法获得

@Retention(RetentionPolicy.RUNTIME)  // 注解会在class字节码文件中存在,在运行时可以通过反射获取到

@Target:注解的作用目标   

@Target(ElementType.TYPE)   //接口、类、枚举

@Target(ElementType.FIELD) //字段、枚举的常量

@Target(ElementType.METHOD) //方法

@Target(ElementType.PARAMETER) //方法参数

@Target(ElementType.CONSTRUCTOR)  //构造函数

@Target(ElementType.LOCAL_VARIABLE)//局部变量

扫描二维码关注公众号,回复: 8498800 查看本文章

@Target(ElementType.ANNOTATION_TYPE)//注解

@Target(ElementType.PACKAGE) ///包   

2、对注解做反射完成想要的效果:

public class MyTool {
    public MyTool() {
    }

    public static void init(Activity activity) {
        try {
            bindView(activity); //调用下面这个方法
        } catch (IllegalAccessException var2) {
            var2.printStackTrace();
        } catch (IllegalArgumentException var3) {
            var3.printStackTrace();
        }
    }

    private static void bindView(Activity activity) throws IllegalAccessException, IllegalArgumentException {
        Class clazz = activity.getClass(); //获取当前Activity的类对象
        Field[] declaredFields = clazz.getDeclaredFields(); //获取这个类对象里面所有的字段(数组集合)
        for(int i = 0; i < declaredFields.length; ++i) { //遍历这个数组
            Field field = declaredFields[i]; //拿到单个字段
            BindView bind = (BindView)field.getAnnotation(BindView.class); //拿到字段上面的BindView注解
            if (bind != null) { //如果有BindView注解的话
                int value = bind.value(); //获取注解里面的int值,也就是我们要的id
                View findViewById = activity.findViewById(value); //找到这个View
                field.setAccessible(true); //取消Java的权限控制检查
                field.set(activity, findViewById); //把该字段和view联系起来
            }
        }
    }
}

说的很清楚了,至此,我们的findViewById的注解BindView就可以用了 


接下来是对onClick点击事件的绑定做注解

实现效果:

@ClickView(R.id.btn)
public void click(View v){
    //do something
}

实现原理和字段绑定差不多:


开始实现:

1、声明注解接口,并且指明是对方法做注解,传入的参数也是int类型:

@Target({ElementType.METHOD}) //对方法做注解
@Retention(RetentionPolicy.RUNTIME)
public @interface ClickView {
    int value();
}

2、获取有该注解的方法进行绑定OnClick事件(和刚刚的MyTool写在一起吧,整一个MyTool类如下):

public class MyTool{
    public MyTool() {
    }

    public static void init(Activity activity) {
        try {
            bindView(activity);
            bindClickEvent(activity);
        } catch (IllegalAccessException var2) {
            var2.printStackTrace();
        } catch (IllegalArgumentException var3) {
            var3.printStackTrace();
        }
    }
    
    private static void bindView(Activity activity) throws IllegalAccessException, IllegalArgumentException {
        Class clazz = activity.getClass();
        Field[] declaredFields = clazz.getDeclaredFields();
        for(int i = 0; i < declaredFields.length; ++i) {
            Field field = declaredFields[i];
            BindView bind = (BindView)field.getAnnotation(BindView.class);
            if (bind != null) {
                int value = bind.value();
                View findViewById = activity.findViewById(value);
                field.setAccessible(true);
                field.set(activity, findViewById);
            }
        }
    }
    
    private static void bindClickEvent(final Activity activity) {
        Class clazz = activity.getClass();
        Method[] declaredMethods = clazz.getDeclaredMethods(); //获取到这个类的所有方法
        
        for(int i = 0; i < declaredMethods.length; ++i) { //遍历
            final Method method = declaredMethods[i];
            ClickView clickView = (ClickView)method.getAnnotation(ClickView.class); //获取方法上面为ClickView的注解
            if (clickView != null) {
                int value = clickView.value(); //拿参数:获取到view的id
                final View findViewById = activity.findViewById(value); //找到这个view
                findViewById.setOnClickListener(new OnClickListener() { //给view设置点击事件
                    public void onClick(View arg0) {
                        method.setAccessible(true); //别忘记了这个,才能拿到method下面的私有属性
                        method.invoke(activity, findViewById); //该方法和这个view建立点击事件的联系
                    }
                });
            }
        }
    }
}

最后,就可以把这个类和两个注解接口打包成lib的jar导入项目中使用了。

完。

发布了60 篇原创文章 · 获赞 13 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/qq_35584878/article/details/99717346