文章目录
- Android 基于反射实现简易版ButterKnife
- 定义注解
- 定义绑定类解析注解
- 使用
- 代码下载
Android 基于反射实现简易版ButterKnife
反射比较消耗资源,一般不推荐使用。
定义注解
/*** 用于绑定元素*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface BindView {@IdRes int value();
}
/*** 定义元注解*/
@Target(ElementType.ANNOTATION_TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface EventType {Class methodClass(); //方法所在的ClassString methodName(); //方法名
}
/*** 绑定点击事件*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@EventType(methodClass = View.OnClickListener.class, methodName = "setOnClickListener")
public @interface OnClick {@IdRes int[] value() default {};
}
/*** 绑定长按事件*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@EventType(methodClass = View.OnLongClickListener.class, methodName = "setOnLongClickListener")
public @interface OnLongClick {@IdRes int[] value() default {};
}
定义绑定类解析注解
public class MyButterKnife {public static void bind(Activity activity) {//获取类中所有变量Field[] fields = activity.getClass().getDeclaredFields();//获取类中所有方法Method[] methods = activity.getClass().getDeclaredMethods();bindFields(activity, fields);bindMethods(activity, methods);}/*** 绑定变量** @param activity* @param fields*/private static void bindFields(Activity activity, Field[] fields) {for (Field field : fields) {//判断是否被@BindView注解if (field.isAnnotationPresent(BindView.class)) {//获取@BindView注解BindView bindView = field.getAnnotation(BindView.class);if (bindView != null) {//设置访问权限if (!field.isAccessible()) {field.setAccessible(true);}//获取注解值int id = bindView.value();//获取ViewView view = activity.findViewById(id);try {//通过反射设置值field.set(activity, view);} catch (IllegalAccessException e) {e.printStackTrace();}}}}}/*** 绑定方法** @param activity* @param methods*/private static void bindMethods(Activity activity, Method[] methods) {for (Method method : methods) {//判断是否被@OnClick或@OnLongClick注解if (method.isAnnotationPresent(OnClick.class) || method.isAnnotationPresent(OnLongClick.class)) {//获取方法上的所有注解Annotation[] annotations = method.getAnnotations();//遍历注解for (Annotation annotation : annotations) {//获取注解的注解类型Class<? extends Annotation> annotationType = annotation.annotationType();//判断注解是否为@EventTypeif (annotationType.isAnnotationPresent(EventType.class)) {//获取EventType注解EventType eventType = annotationType.getAnnotation(EventType.class);assert eventType != null;//获取方法的ClassClass methodClass = eventType.methodClass();//获取方法名String methodName = eventType.methodName();//设置访问权限method.setAccessible(true);try {//获取OnClick或OnLongClick的value值Method valueMethod = annotationType.getDeclaredMethod("value");//获取绑定的idint[] viewIds = (int[]) valueMethod.invoke(annotation);//代理对象Object proxy = Proxy.newProxyInstance(methodClass.getClassLoader(),new Class[]{methodClass},new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method m, Object[] args) throws Throwable {return method.invoke(activity, args);}});assert viewIds != null;//遍历id并绑定事件for (int id : viewIds) {//获取Activity的ViewView view = activity.findViewById(id);//获取指定方法,如setOnClickListener方法,参数类型是OnClickListenerMethod clickMethod = view.getClass().getMethod(methodName, methodClass);//执行方法clickMethod.invoke(view, proxy);}} catch (Exception e) {e.printStackTrace();}}}}}}
}
使用
public class MainActivity extends AppCompatActivity {@BindView(R.id.textView)TextView textView;@BindView(R.id.imageView)ImageView imageView;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);MyButterKnife.bind(this);textView.setText("hello");imageView.setImageResource(R.mipmap.ic_launcher);}@OnClick({R.id.btn1, R.id.btn2})public void click(View view) {switch (view.getId()) {case R.id.btn1:Toast.makeText(this, "btn1 click", Toast.LENGTH_SHORT).show();break;case R.id.btn2:Toast.makeText(this, "btn2 click", Toast.LENGTH_SHORT).show();break;}}@OnLongClick({R.id.btn1, R.id.btn2})public boolean longClick(View view) {switch (view.getId()) {case R.id.btn1:Toast.makeText(this, "btn1 longClick", Toast.LENGTH_SHORT).show();break;case R.id.btn2:Toast.makeText(this, "btn2 longClick", Toast.LENGTH_SHORT).show();break;}return true;}
}