ButterKnife注解框架相信大家都是用过,记得以前的老大老是说黄油刀,黄油刀的,那里面的实现原理是什么呢?其实内部原理比较简单, 简单的你看文本文也可以自己写
编译时注解实现
1,定义接口,成员变量的
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface InjectView {
int value();
}
这个injectView 接口的名字可以自己定义,但一般做到见名知意里面的@Target 等注解看统一专题里面的详解。都是注解的内容,里面的是生命周期等属性的限制
2.定义点击事件的接口
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface OnClick {
int[] value();
}
3.写一个工具类也就是相当于 Butterknife.bind(this)效果:
/**
* 文件描述: 代码注入工具类
* Created by xn069392
* 创建时间 2018/8/2
*/
public class InjectViewUtils {
/**
* 代码注入方法,相当于Butterknife的 bind()
*
* @param activity
*/
public static void inject(final Activity activity) {
//反射拿到类对象
Class extends Activity> clazz = activity.getClass();
//这里我们需要的是所有的成员变量的参数
Field[] Fileds = clazz.getDeclaredFields();
//遍历集合
for (int i = 0; i < Fileds.length; i++) {
//获取每一个成员变量
Field filed = Fileds[i];
// 如果私有 暴力反射
filed.setAccessible(true);
//获取到成员变量的注解,传入参数就是之前我们定义的接口的类对象
InjectView inject = filed.getAnnotation(InjectView.class);
if (inject != null) {
//我们的接口中定义了一个int 类型的value 值 ,获取到value 也就是我们成员变量的id
int id = inject.value();
//通过这个ID,也是需要在传入Activity中去找到对应view的
View view = activity.findViewById(id);
//成员变量找到了,这个要去设置
try {
filed.set(activity, view);
} catch (IllegalAccessException e) {
Log.e(TAG, "inject: 设置成员变量失败!");
e.printStackTrace();
}
}
}
//处理点击事件
Method[] declaredMethods = clazz.getDeclaredMethods();
for (int i = 0; i < declaredMethods.length; i++) {
final Method method = declaredMethods[i];
method.setAccessible(true);
OnClick onClick = method.getAnnotation(OnClick.class);
//为什么是一个数组呢,因为我们的点击事件 有事后就写一个方法,多个id .
int[] value = onClick.value();
for (int j = 0; j < value.length; j++) {
int idValue = value[j];
final View viewById = activity.findViewById(idValue);
viewById.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
try {
method.invoke(activity, viewById);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
});
}
}
}
}
上面的代码主要是用到暴力反射,
4.在主方法中调用
public class MainActivity extends AppCompatActivity {
@InjectView(R.id.button1)
Button mButton;
@InjectView(R.id.button2)
Button mButton2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
InjectViewUtils.inject(this);
mButton.setText("我是第一个button");
}
@OnClick({R.id.button1,R.id.button2})
private void XXX(View view ){
switch (view.getId()){
case R.id.button1:
Toast.makeText(this,"第一个按钮的手动编译时注解",Toast.LENGTH_LONG).show();
break;
case R.id.button2:
Toast.makeText(this,"第222个按钮的手动编译时注解,主要用到反射",Toast.LENGTH_LONG).show();
break;
}
}
}package com.xiaoniu.finance.butterknifesimple;
import android.app.Activity;
import android.util.Log;
import android.view.View;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import static android.content.ContentValues.TAG;
/**
* 文件描述: 代码注入工具类
* Created by xn069392
* 创建时间 2018/8/2
*/
public class InjectViewUtils {
/**
* 代码注入方法,相当于Butterknife的 bind()
*
* @param activity
*/
public static void inject(final Activity activity) {
//反射拿到类对象
Class extends Activity> clazz = activity.getClass();
//这里我们需要的是所有的成员变量的参数
Field[] Fileds = clazz.getDeclaredFields();
//遍历集合
for (int i = 0; i < Fileds.length; i++) {
//获取每一个成员变量
Field filed = Fileds[i];
// 如果私有 暴力反射
filed.setAccessible(true);
//获取到成员变量的注解,传入参数就是之前我们定义的接口的类对象
InjectView inject = filed.getAnnotation(InjectView.class);
if (inject != null) {
//我们的接口中定义了一个int 类型的value 值 ,获取到value 也就是我们成员变量的id
int id = inject.value();
//通过这个ID,也是需要在传入Activity中去找到对应view的
View view = activity.findViewById(id);
//成员变量找到了,这个要去设置
try {
filed.set(activity, view);
} catch (IllegalAccessException e) {
Log.e(TAG, "inject: 设置成员变量失败!");
e.printStackTrace();
}
}
}
//处理点击事件
Method[] declaredMethods = clazz.getDeclaredMethods();
for (int i = 0; i < declaredMethods.length; i++) {
final Method method = declaredMethods[i];
method.setAccessible(true);
OnClick onClick = method.getAnnotation(OnClick.class);
//为什么是一个数组呢,因为我们的点击事件 有事后就写一个方法,多个id .
//这里有的方法没有注解,必须做空判断
if(onClick !=null){
int[] value = onClick.value();
for (int j = 0; j < value.length; j++) {
int idValue = value[j];
final View viewById = activity.findViewById(idValue);
viewById.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
try {
method.invoke(activity, viewById);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
});
}
}
}
}
}
5.效果的实现
6.源码地址:
https://github.com/zh2016hz/ButterknifeSimple.git