Android反射实现ButterKnife的@BindView和@OnClick

287 阅读2分钟

@BindView 替代findViewById

  1. 新建自定义注解类
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)//作用在参数上
public @interface BindView{
    int value() default 0;//注解传入的参数
}

  1. 通过反射得到将注解传入的参数赋值给对应的注解对象
public class SBindKinf {

  public static void bindField(Activity activity) {
        Class cla = activity.getClass();//得到Class对象
        Field[] fields = cla.getDeclaredFields();//获得对象的所有声明的字段 但是不包括父类的申明字段

        for (Field f : fields
        ) {
              //得到被BindView注解的参数对象
            BindView bindView = f.getAnnotation(BindView.class);
            if (bindView != null) {//当前参数是否被@BindView注解
                View view = activity.findViewById(bindView.value());//通过注解的参数得到View对象

                f.setAccessible(true);//未设置Field的setAccessible方法为true时,会在调用的时候进行访问安全检查,会抛出IllegalAccessException异常
                try {
                    f.set(activity, view);//将view对象赋值给当前的被注解参数
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }

            }

        }
    }



}

  1. 在setContentView之后执行SBindKinf.bindField
  2. 对应参数添加@BindView即可

@OnClick 替代setOnClickListener

  1. 新建自定义注解类
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)//作用在方法上
public @interface OnClick{
    int value() default 0;//注解传入的参数
}

  1. 通过反射得到将注解传入的参数赋值给对应的注解对象
public class SBindKinf {

 public static void bindClick(Activity activity) {
        Class cla = activity.getClass();
      方法
        for (Method me : methods
        ) {
            OnClick click = me.getAnnotation(OnClick.class);
            if (click != null) {//判断当前方法是否被@OnClick注解
                me.setAccessible(true);
                View view = activity.findViewById(click.value());//得到View对象
                view.setOnClickListener(new View.OnClickListener() {//帮助完成点击事件的设置
                    @Override
                    public void onClick(View v) {
                        try {
                            me.invoke(activity);//将逻辑交还给被注解的方法
                        } catch (IllegalAccessException e) {
                            e.printStackTrace();
                        } catch (InvocationTargetException e) {
                            e.printStackTrace();
                        }
                    }
                });

            }

        }

    }


}

  1. 在setContentView之后执行SBindKinf.bindClick
  2. 对应方法添加@OnClick

最终代码

public class SBindKinf {


    public static void bind(Activity activity) {
        bindField(activity);
        bindClick(activity);
    }


    private static void bindField(Activity activity) {
        Class cla = activity.getClass();
        Field[] fields = cla.getDeclaredFields();

        for (Field f : fields
        ) {
            BindView bindView = f.getAnnotation(BindView.class);
            if (bindView != null) {
                View view = activity.findViewById(bindView.value());

                f.setAccessible(true);
                try {
                    f.set(activity, view);
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }

            }

        }
    }

    private static void bindClick(Activity activity) {
        Class cla = activity.getClass();
        Method[] methods = cla.getDeclaredMethods();
        for (Method me : methods
        ) {

            OnClick click = me.getAnnotation(OnClick.class);
            if (click != null) {
                me.setAccessible(true);
                View view = activity.findViewById(click.value());
                view.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        try {
                            me.invoke(activity);
                        } catch (IllegalAccessException e) {
                            e.printStackTrace();
                        } catch (InvocationTargetException e) {
                            e.printStackTrace();
                        }
                    }
                });

            }

        }

    }
}