作为一个Android菜鸟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();
}
}
});
}
}
}
}