自定义ButterKnife

作为一个Android菜鸟ButterKnife这个框架相信大家都使用过,但是更多的只停留在会用的层面上,对于它的底层如何实现还是一无所知

ButterKnife

在学习ButterKnife的时候,先要了解两样东西,就是反射和注解

一、反射

1、何为反射?

反射就是把Java类中的各种成分映射成Java类
一个类中的每个成员都可以用相应的反射API类中的一个实例表示(Feild、Method、Contructor、Package)

先定义一个User类

public class User {

    private String name;
    public int age;

    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public void eat(String eat) {
        Log.e("---------", eat + "非常好吃");
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

反射的操作

/********获取类对象***********/

        //方法1
        Class clazz1 = User.class;

        //方法2
        try {
            Class clazz2 = Class.forName("com.example.administrator.mybutterknife.User");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

        //方法3
        User user = new User("李易峰", 30);
        Class clazz3 = user.getClass();

        try {
            //得到成员变量对象
            //getField只能得到Public
            Field fieldAge = clazz3.getField("age");
            //getDeclaredField可以取出private
            Field fieldName = clazz3.getDeclaredField("name");
            //允许对对象进行操作(暴力反射)
            fieldName.setAccessible(true);
            //获取字段的值
            String name = (String) fieldName.get(user);
            int age = fieldAge.getInt(user);

            Log.e("---------------", name + "-----" + age);

            /********修改对象中变量的值************/
            fieldName.set(user, "刘亦菲");
            fieldAge.setInt(user, 40);
            String name2 = (String) fieldName.get(user);
            int age2 = fieldAge.getInt(user);
            Log.e("---------------", name2 + "-----" + age2);

        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }

        /*************对象中的方法****************/
        //取出所有方法
        /*Method[] methods = clazz3.getMethods();
        for (Method method : methods) {
            Log.e("---------------", method.getName());
        }*/

        try {
            //取到eat方法参数一,方法名称,参数二:参数类型
            Method eat = clazz3.getMethod("eat", String.class);
            //调用方法
            eat.invoke(user, "米饭");

        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }

二、注解

1、定义注解

//@Target(ElementType.FIELD)//定义当前注解使用在变量上
//@Target(ElementType.METHOD)//定义当前注解使用在方法上
//@Retention(RetentionPolicy.SOURCE)//该注解存在于源码中,当源码被编译成字节码的时候,该注解被清除
//@Retention(RetentionPolicy.CLASS)//该注解存在于字节码中,当源码被编译成字节码的时候,该注解不会被清除
@Retention(RetentionPolicy.RUNTIME)//表示当前注解存在与java虚拟机中
@Target(ElementType.FIELD)
public @interface BindView {

    String name();

    int age();

}

2、使用注解的类

public class Student {

    @BindView(name = "zhangsan", age = 10)
    private String name;

    private int age;

    public void study() {

    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

3、对使用了注解类的类进行反射操作的类

public class ButterKnife {

    public static void bind(Student student) {
        //2、获取student对象对应的字节码
        Class clazz = student.getClass();

        try {
            //3、通过反射拿到name和age
            Field fieldName = clazz.getDeclaredField("name");
            Field fieldAge = clazz.getDeclaredField("age");
            //允许暴力反射
            fieldName.setAccessible(true);
            fieldAge.setAccessible(true);

            //获取name字段的注解
            BindView bindView = fieldName.getAnnotation(BindView.class);

            if (bindView != null) {
                //获取注解的值
                String name = bindView.name();
                int age = bindView.age();
                //设置对象的属性值
                fieldName.set(student, name);
                fieldAge.setInt(student, age);
            }

        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }
}

三、自定义ButterKnife

1、定义BindView、OnClick注解

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface BindView {
    int value();
}


@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface OnClick {
    int value();
}

2、使用BindView、OnClick注解

 @BindView(R.id.tv1)
    private TextView tv1;
    @BindView(R.id.tv2)
    private TextView tv2;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ButterKnife.bind(this);
        Toast.makeText(this, tv1.getText().toString(), Toast.LENGTH_SHORT).show();
    }

@OnClick(R.id.btn)
    public void onClick(){
        Toast.makeText(this, tv1.getText().toString(), Toast.LENGTH_SHORT).show();
    }

3、定义ButterKnife类

public class ButterKnife {

    public static void bind(Activity activity) {
        try {
            bindView(activity);
            bindOnClick(activity);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void bindView(Activity activity) throws IllegalAccessException {
        //1、获取字节码
        Class<? extends Activity> aClass = activity.getClass();
        //2、获取activity中的所有变量
        Field[] declaredFields = aClass.getDeclaredFields();
        //3、遍历变量数组
        for (Field field : declaredFields) {
            //允许暴力反射
            field.setAccessible(true);
            //获取变量上的注解
            BindView annotation = field.getAnnotation(BindView.class);
            if (annotation != null) {
                //获取注解上的值
                int id = annotation.value();
                //通过ID获取控件
                View view = activity.findViewById(id);
                //给字段赋值
                field.set(activity, view);
            }
        }
    }

    private static void bindOnClick(final Activity activity) {
        //1、获取字节码
        Class<? extends Activity> aClass = activity.getClass();
        //2、获取activity中的所有方法
        Method[] declaredMethods = aClass.getDeclaredMethods();
        //3、遍历方法数组
        for (final Method method : declaredMethods) {
            method.setAccessible(true);
            OnClick annotation = method.getAnnotation(OnClick.class);
            if (annotation != null) {
                int id = annotation.value();
                View view = activity.findViewById(id);
                view.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View view) {
                        try {
                            method.invoke(activity,null);
                        } catch (IllegalAccessException e) {
                            e.printStackTrace();
                        } catch (InvocationTargetException e) {
                            e.printStackTrace();
                        }
                    }
                });
            }
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值