教你10分钟手敲 Butter Knife(小刀注解)
在用 AndroidStudio 集成 Butter Knife(小刀注解)的时候感觉像极了J2EE的Spring IOC容器 自己研究了一下,我来分享一下,小编会:多注释,多贴码,尽量降低同学们的学习时间成本,希望喜欢 花里胡哨 的同学不容错过。(求关注(✪ω✪))
简单介绍Butter Knife(小刀注解)是什么鬼:
原生的获取组件是这样的:
public class MainActivity extends AppCompatActivity {//定义组件private TextView main_tv;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);main_tv = findViewById(R.id.main_tv);//获取组件main_tv.setText("卡哇伊");//使用组件}
}
使用 Butter Knife(小刀注解)后的获取组件是这样子的:
public class MainActivity extends AppCompatActivity {@BindView(R.id.main_tv) private TextView main_tv;//定义组件@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);ButterKnife.bind(this); //绑定activitymain_tv.setText("卡哇伊");//使用组件}}
在实际项目中有什么好处呢?
1、强大的View绑定和Click事件处理功能,简化代码,提升开发效率 2、方便的处理Adapter里的ViewHolder绑定问题 3、运行时不会影响APP效率,使用配置方便 4、代码清晰,可读性强 |
利用插件一键生成,爽到嗨。省去了 findViewById 。不就是利用注解赋值嘛,来小编带你10分钟搞定。
第一步:新建一共空的工程,并新建必要的文件目录 annotation、entity、fragment、util:
第二步:在 新建一个注解 取名为 GT_View 并添加相应代码:
GT_View 注解代码:
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface GT_View {int value();
}
第三步:新建一个 GT_Util.java 的Java文件:
GT_Util 代码:(直接复制粘贴,代码有注释,Java基础好点的看懂的快些)
public class GT_Util {/*** 注入所有注解* @param activity*/public static void initAll(Activity activity){initView(activity); //为加载 组件 初始化}/***注入控件* @param activity*/private static void initView(Activity activity){Class<? extends Activity> clazz = activity.getClass(); //获取该类信息Field[] fields = clazz.getDeclaredFields(); //获致所有成员变更for (Field field:fields) { //遍历所有当前 Activity 的成员变量GT_View initView = field.getAnnotation(GT_View.class); //获取当前变量的 GT_View 注解if(initView != null){ //如果为 null 则表明当前成员变量没有被 GT_View 注解标注int viewId = initView.value(); //获取当前注解上标注的 组件IDtry {Method method = clazz.getMethod("findViewById", int.class); //获取当前Activity中 findViewById 方法method.setAccessible(true); //设置 findViewById 方法的 访问权限field.setAccessible(true); //设置 当前成员变量的 访问权限Object object = method.invoke(activity, viewId); //注入数据:将ID 注入到 findViewById 中 并返回 Viewfield.set(activity,object); //将返回的 View 设置到 Activity 中} catch (Exception e) {e.printStackTrace();}}}}}
第四步:修改xml文件,并在Activity添加相应代码:
activity_main.xml 文件:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivity"><TextViewandroid:id="@+id/main_tv"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="Hello World!"android:textSize="24sp"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintLeft_toLeftOf="parent"app:layout_constraintRight_toRightOf="parent"app:layout_constraintTop_toTopOf="parent" /></androidx.constraintlayout.widget.ConstraintLayout>
MainActivity.java 文件:
public class MainActivity extends AppCompatActivity {@GT_View(R.id.main_tv)private TextView main_tv; //定义组件@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);GT_Util.initAll(this); //绑定Activitymain_tv.setText("卡哇伊"); //使用组件}}
运行效果图:
总结:简单吧,10分钟做到这里差不多了,感谢你的阅读。٩(๑>◡<๑)۶
如果你并不满足于此,请继续阅读下面。
关注博主最新发布库:GitHub - 1079374315/GT
如果你并不满足于此,不如再花10分钟来搞定这些? 求关注(◕ᴗ◕✿)
@GT_Activity(R.layout.activity_main)//省去了 setContentView 方法
public class MainActivity extends AppCompatActivity {@GT_View(R.id.ioc_tv)private TextView tv;//获取View组件@GT_Object(valueString = "1079",valueInt = 21,types = {GT_Object.TYPE.STRING, GT_Object.TYPE.INT}, functions = {"setUsername","setAge"})private LoginBean loginBean;//获取带参数的实体类@GT_Res.GT_String(R.string.StringTest)private String data;//注入 res下string 字符串资源@GT_Res.GT_Color(R.color.colorTest)private int MyColor;//注入 res下color 颜色资源@GT_Res.GT_Drawable(R.drawable.ic_launcher_background)private Drawable btnBG;//注入 res下drawable 图片资源@GT_Res.GT_Dimen(R.dimen.tv_size)private float TextSize;//注入 res下dimen 尺寸资源@GT_Res.GT_Animation(R.anim.alpha)private Animation animation;//注入 res下anim 动画资源 @GT_Res.GT_StringArray(R.array.ctype)private String[] strArray;//注入 res下array string数组资源 @GT_Res.GT_IntArray(R.array.textInt)private int[] intArray;//注入 res下array int数组资源 @GT_Res.GT_Layout(R.layout.activity_main)private View layout;//注入 res下array 布局资源 @Collection.List({Fragment_1.class,Fragment_2.class,Fragment_3.class})List<Object> fragmentList;//实例化3个Fragment并注入到List中@Collection.Map({Fragment_1.class,Fragment_2.class,Fragment_3.class})Map<Object,Object> fragmentMap;//实例化3个Fragment并注入到Map中@Collection.Set({Fragment_1.class,Fragment_2.class,Fragment_3.class})Set<Object> fragmentSet;//实例化3个Fragment并注入到Set中@GT_Click({R.id.ioc_btn01,R.id.ioc_btn02,R.id.ioc_btn03})public void testBtnOnCLick(View view){//监听多按钮单击事件
既然你往下滑,那说明我们都是 好奇心 强的人,说好10分钟,我们时间紧迫赶紧的。(๑╹◡╹)ノ"""
第一步:添加必要的注解类 :
Collection、GT_Activity、GT_Click、GT_Object、GT_Res、GT_View、OnClickEvent
Collection:注解代码如下
/*** 集合注解*/
public @interface Collection {/*** List 注解*/@Target(ElementType.FIELD)@Retention(RetentionPolicy.RUNTIME)@interface List {Class[] value();}/*** Map 注解*/@Target(ElementType.FIELD)@Retention(RetentionPolicy.RUNTIME)@interface Map {Class[] value();}/*** Set 注解*/@Target(ElementType.FIELD)@Retention(RetentionPolicy.RUNTIME)@interface Set {Class[] value();}}
GT_Activity:注解代码如下
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface GT_Activity {int value();
}
GT_Click:注解代码如下
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@OnClickEvent(listenerType = View.OnClickListener.class,listenerSetter = "setOnClickListener",methodName = "onClick")
public @interface GT_Click {int[] value();
}
GT_Object:注解代码如下
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface GT_Object {interface TYPE {String BYTE = "byte";String SHORT = "short";String INT = "int";String LONG = "long";String FLOAT = "float";String DOUBLE = "double";String BOOLEAN = "boolean";String CHAR = "char";String STRING = "String";String BYTES = "bytes";String SHORTS = "shorts";String INTS = "ints";String LONGS = "longs";String FLOATS = "floats";String DOUBLES = "doubles";String BOOLEANS = "booleans";String CHARS = "chars";String STRINGS = "Strings";}/** 单参数的传递 **/byte valueByte() default 0;short valueShort() default 0;int valueInt() default 0;long valueLong() default 0L;float valueFloat() default 0.0f;double valueDouble() default 0.0d;boolean valueBoolean() default false;char valueChar() default 0;String valueString() default "";/** 多参数的传递 **/byte[] valueBytes() default {};short[] valueShorts() default {};int[] valueInts() default {};long[] valueLongs() default {};float[] valueFloats() default {};double[] valueDoubles() default {};boolean[] valueBooleans() default {};char[] valueChars() default {};String[] valueStrings() default {};/** 修改参数的类型 **/String type() default "";String[] types() default {};/** 要赋值的方法 **/String function() default "";String[] functions() default {};}
GT_Res:注解代码如下
/*** 资源注解*/
public @interface GT_Res {/*** 字符串 注解*/@Target(ElementType.FIELD)@Retention(RetentionPolicy.RUNTIME)@interface GT_String {int value();}/*** 颜色 注解*/@Target(ElementType.FIELD)@Retention(RetentionPolicy.RUNTIME)@interface GT_Color {int value();}/*** 尺寸 注解*/@Target(ElementType.FIELD)@Retention(RetentionPolicy.RUNTIME)@interface GT_Dimen {int value();}/*** 图片 注解*/@Target(ElementType.FIELD)@Retention(RetentionPolicy.RUNTIME)@interface GT_Drawable {int value();}/*** 动画 注解*/@Target(ElementType.FIELD)@Retention(RetentionPolicy.RUNTIME)@interface GT_Animation {int value();}/*** 字符串数组 注解*/@Target(ElementType.FIELD)@Retention(RetentionPolicy.RUNTIME)@interface GT_StringArray {int value();}/*** 整数数组 注解*/@Target(ElementType.FIELD)@Retention(RetentionPolicy.RUNTIME)@interface GT_IntArray {int value();}/*** 将 xml 文件解析成 View 注解*/@Target(ElementType.FIELD)@Retention(RetentionPolicy.RUNTIME)@interface GT_Layout {int value();}}
OnClickEvent:注解代码如下
@Target(ElementType.ANNOTATION_TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface OnClickEvent {Class<?> listenerType();//接口类型String listenerSetter();//设置的方法String methodName();//接口里面要实现的方法
}
第二步:更新 GT_Util.java 文件
注意:代码有点多(接近千行),但原理都与上面详细讲解的差异不多所以就直接贴码了。
public class GT_Util {//Fragment 注入public static void initAll(Object object, View view){initView(object,view); //为加载 组件 初始化initClick(object,view); //为加载 组件单击 初始化initObject(object); //为加载 Object 成员变量初始化initList(object); //为加载 List 成员变量初始化initMap(object); //为加载 Map 成员变量初始化initSet(object); //为加载 Set 成员变量初始化initAnimation(object,view); //为加载 Animation 资源初始化initDimen(object,view); //为加载 Dimen 资源初始化initDrawable(object,view); //为加载 Style 资源初始化initColor(object,view); //为加载 Color 资源初始化initString(object,view); //为加载 String 资源初始化initIntArray(object,view); //为加载 IntArray 资源初始化initStringArray(object,view); //为加载 StringArray 资源初始化initLayout(object,view); //为加载 Layout 资源初始化}/*** Fragment 中的使用*//** Fragment 注入控件*/private static void initView(Object object,View view){Class<? extends Object> clazz = object.getClass();//获取该类信息Field[] fields = clazz.getDeclaredFields();//获致所有成员变更for (Field field:fields) {GT_View initView = field.getAnnotation(GT_View.class);if(initView != null){int viewId = initView.value();try {View viewById = view.findViewById(viewId);field.setAccessible(true);field.set(object,viewById);} catch (Exception e) {e.printStackTrace();}}}}/** 注入点击事件 */private static void initClick(Object object,View view){Class<? extends Object> clazz = object.getClass();Method[] methods= clazz.getMethods();//获取所有声明为公有的方法for (Method method:methods){//遍历所有公有方法Annotation[] annotations = method.getAnnotations();//获取该公有方法的所有注解for (Annotation annotation:annotations){//遍历所有注解Class<? extends Annotation> annotationType = annotation.annotationType();//获取具体的注解类OnClickEvent onClickEvent = annotationType.getAnnotation(OnClickEvent.class);//取出注解的onClickEvent注解if(onClickEvent!=null){//如果不为空try {Method valueMethod=annotationType.getDeclaredMethod("value");//获取注解InjectOnClick的value方法int[] viewIds= (int[]) valueMethod.invoke(annotation, (Object[]) null);//获取控件值Class<?> listenerType = onClickEvent.listenerType();//获取接口类型String listenerSetter = onClickEvent.listenerSetter();//获取set方法String methodName = onClickEvent.methodName();//获取接口需要实现的方法MyInvocationHandler handler = new MyInvocationHandler(object);//自己实现的代码,负责调用handler.setMethodMap(methodName,method);//设置方法及设置方法Object object2 = Proxy.newProxyInstance(listenerType.getClassLoader(),new Class<?>[]{listenerType},handler);//创建动态代理对象类for (int viewId:viewIds){//遍历要设置监听的控件View view2 = view.findViewById(viewId);//获取该控件Method m = view2.getClass().getMethod(listenerSetter, listenerType);//获取方法m.invoke(view2,object2);//调用方法}} catch (Exception e) {e.printStackTrace();}}}}}/** 注入 Animation 资源字符串 **/private static void initAnimation(Object object, View view) {Class<? extends Object> clazz = object.getClass();//获取该类信息Field[] fields=clazz.getDeclaredFields();//获致所有成员变更for (Field field:fields) {GT_Res.GT_Animation initView = field.getAnnotation(GT_Res.GT_Animation.class);if(initView!=null){int viewRes = initView.value();try {Context context = view.getContext();if(context != null){Animation animation = AnimationUtils.loadAnimation(context, viewRes);field.setAccessible(true);field.set(object,animation);}} catch (Exception e) {e.printStackTrace();}}}}/** 注入 Dimen 资源字符串 **/private static void initDimen(Object object, View view) {Class<? extends Object> clazz = object.getClass();//获取该类信息Field[] fields=clazz.getDeclaredFields();//获致所有成员变更for (Field field:fields) {GT_Res.GT_Dimen initView = field.getAnnotation(GT_Res.GT_Dimen.class);if(initView!=null){int viewRes = initView.value();try {float dimension = view.getResources().getDimension(viewRes);field.setAccessible(true);field.set(object,dimension);} catch (Exception e) {e.printStackTrace();}}}}/** 注入 Drawable 资源字符串 **/private static void initDrawable(Object object, View view) {Class<? extends Object> clazz = object.getClass();//获取该类信息Field[] fields=clazz.getDeclaredFields();//获致所有成员变更for (Field field:fields) {GT_Res.GT_Drawable initView = field.getAnnotation(GT_Res.GT_Drawable.class);if(initView!=null){int viewRes = initView.value();try {Drawable drawable = view.getResources().getDrawable(viewRes);field.setAccessible(true);field.set(object,drawable);} catch (Exception e) {e.printStackTrace();}}}}/** 注入 Color 资源字符串 **/private static void initColor(Object object, View view) {Class<? extends Object> clazz = object.getClass();//获取该类信息Field[] fields=clazz.getDeclaredFields();//获致所有成员变更for (Field field:fields) {GT_Res.GT_Color initView = field.getAnnotation(GT_Res.GT_Color.class);if(initView!=null){int viewRes = initView.value();try {int color = view.getResources().getColor(viewRes);field.setAccessible(true);field.set(object,color);} catch (Exception e) {e.printStackTrace();}}}}/** 注入 String 资源字符串 **/private static void initString(Object object, View view) {Class<? extends Object> clazz = object.getClass();//获取该类信息Field[] fields=clazz.getDeclaredFields();//获致所有成员变更for (Field field:fields) {GT_Res.GT_String initView = field.getAnnotation(GT_Res.GT_String.class);if(initView!=null){int viewRes = initView.value();try {String string = view.getResources().getString(viewRes);field.setAccessible(true);field.set(object,string);} catch (Exception e) {e.printStackTrace();}}}}/** 注入 Int 资源字符串数组 **/private static void initIntArray(Object object, View view) {Class<? extends Object> clazz = object.getClass();//获取该类信息Field[] fields=clazz.getDeclaredFields();//获致所有成员变更for (Field field:fields) {GT_Res.GT_IntArray initView = field.getAnnotation(GT_Res.GT_IntArray.class);if(initView!=null){int viewRes = initView.value();try {int[] intArray = view.getResources().getIntArray(viewRes);field.setAccessible(true);field.set(object,intArray);} catch (Exception e) {e.printStackTrace();}}}}/** 注入 String 资源字符串数组 **/private static void initStringArray(Object object, View view) {Class<? extends Object> clazz = object.getClass();//获取该类信息Field[] fields=clazz.getDeclaredFields();//获致所有成员变更for (Field field:fields) {GT_Res.GT_StringArray initView = field.getAnnotation(GT_Res.GT_StringArray.class);if(initView!=null){int viewRes = initView.value();try {String[] stringArray = view.getResources().getStringArray(viewRes);field.setAccessible(true);field.set(object,stringArray);} catch (Exception e) {e.printStackTrace();}}}}/** 解析 Layout 资源文件成 View **/private static void initLayout(Object object, View view) {Class<? extends Object> clazz = object.getClass();//获取该类信息Field[] fields=clazz.getDeclaredFields();//获致所有成员变更for (Field field:fields) {GT_Res.GT_Layout initView = field.getAnnotation(GT_Res.GT_Layout.class);if(initView!=null){int viewRes = initView.value();try {Context context = view.getContext();if(context != null){View viewLayout = LayoutInflater.from(context).inflate(viewRes, null);field.setAccessible(true);field.set(object,viewLayout);}} catch (Exception e) {e.printStackTrace();}}}}/** 注入 List 资源字符串 **/private static void initList(Object object) {Class<? extends Object> clazz = object.getClass();//获取该类信息Field[] fields=clazz.getDeclaredFields();//获致所有成员变更for (Field field:fields) {Collection.List initView = field.getAnnotation(Collection.List.class);if(initView!=null){Class[] classes = initView.value();List<Object> objectList = new ArrayList<>();//创建一个 ListViewfor(Class cla : classes){String classPage = cla.toString();String[] s = classPage.split(" ");classPage = s[1];//实例化一个对象Object object2 = null;try {object2 = Class.forName(classPage).newInstance();} catch (IllegalAccessException e) {e.printStackTrace();} catch (InstantiationException e) {e.printStackTrace();} catch (ClassNotFoundException e) {e.printStackTrace();}objectList.add(object2);//添加每一个经过反射得到的 对象}try {field.setAccessible(true);field.set(object,objectList);} catch (Exception e) {e.printStackTrace();}}}}/** 注入 Map 资源字符串 **/private static void initMap(Object object) {Class<? extends Object> clazz = object.getClass();//获取该类信息Field[] fields=clazz.getDeclaredFields();//获致所有成员变更for (Field field:fields) {Collection.Map initView = field.getAnnotation(Collection.Map.class);if(initView!=null){Class[] classes = initView.value();Map<Object,Object> objectMap = new HashMap<>();//创建一个 Mapfor(Class cla : classes){String classPage = cla.toString();String[] s = classPage.split(" ");classPage = s[1];//实例化一个对象Object object2 = null;try {object2 = Class.forName(classPage).newInstance();} catch (IllegalAccessException e) {e.printStackTrace();} catch (InstantiationException e) {e.printStackTrace();} catch (ClassNotFoundException e) {e.printStackTrace();}objectMap.put(cla,object2);//保存每个创建出来的 对象 key 为 每个对象的 class}try {field.setAccessible(true);field.set(object,objectMap);} catch (Exception e) {e.printStackTrace();}}}}/** 注入 Set 资源字符串 **/private static void initSet(Object object) {Class<? extends Object> clazz = object.getClass();//获取该类信息Field[] fields=clazz.getDeclaredFields();//获致所有成员变更for (Field field:fields) {Collection.Set initView = field.getAnnotation(Collection.Set.class);if(initView!=null){Class[] classes = initView.value();Set<Object> objectSet = new HashSet<>();//创建一个 Setfor(Class cla : classes){String classPage = cla.toString();String[] s = classPage.split(" ");classPage = s[1];//实例化一个对象Object object2 = null;try {object2 = Class.forName(classPage).newInstance();} catch (IllegalAccessException e) {e.printStackTrace();} catch (InstantiationException e) {e.printStackTrace();} catch (ClassNotFoundException e) {e.printStackTrace();}objectSet.add(object2);//保存每个创建出来的 对象}try {field.setAccessible(true);field.set(object,objectSet);} catch (Exception e) {e.printStackTrace();}}}}/*** Activity 中的使用*//*** activity 注入* @param activity*/public static void initAll(Activity activity){initActivity(activity); //为加载 Activity 布局初始化initView(activity); //为加载 组件 初始化initClick(activity); //为加载 组件单击 初始化initObject(activity); //为加载 Object 成员变量初始化initAnimation(activity); //为加载 Animation 资源初始化initDimen(activity); //为加载 Dimen 资源初始化initDrawable(activity); //为加载 Style 资源初始化initColor(activity); //为加载 Color 资源初始化initString(activity); //为加载 String 资源初始化initIntArray(activity); //为加载 IntArray 资源初始化initStringArray(activity); //为加载 StringArray 资源初始化initLayout(activity); //为加载 Layout 资源初始化}/** 解析 Layout 资源文件成 View **/private static void initLayout(Activity activity) {Class<? extends Activity> clazz = activity.getClass();//获取该类信息Field[] fields=clazz.getDeclaredFields();//获致所有成员变更for (Field field:fields) {GT_Res.GT_Layout initView = field.getAnnotation(GT_Res.GT_Layout.class);if(initView!=null){int viewRes = initView.value();try {View view = LayoutInflater.from(activity).inflate(viewRes, null);field.setAccessible(true);field.set(activity,view);} catch (Exception e) {e.printStackTrace();}}}}/** 注入 Int 资源字符串数组 **/private static void initIntArray(Activity activity) {Class<? extends Activity> clazz = activity.getClass();//获取该类信息Field[] fields=clazz.getDeclaredFields();//获致所有成员变更for (Field field:fields) {GT_Res.GT_IntArray initView = field.getAnnotation(GT_Res.GT_IntArray.class);if(initView!=null){int viewRes = initView.value();try {int[] intArray = activity.getResources().getIntArray(viewRes);field.setAccessible(true);field.set(activity,intArray);} catch (Exception e) {e.printStackTrace();}}}}/** 注入 String 资源字符串数组 **/private static void initStringArray(Activity activity) {Class<? extends Activity> clazz = activity.getClass();//获取该类信息Field[] fields=clazz.getDeclaredFields();//获致所有成员变更for (Field field:fields) {GT_Res.GT_StringArray initView = field.getAnnotation(GT_Res.GT_StringArray.class);if(initView!=null){int viewRes = initView.value();try {String[] stringArray = activity.getResources().getStringArray(viewRes);field.setAccessible(true);field.set(activity,stringArray);} catch (Exception e) {e.printStackTrace();}}}}/** 注入 Animation 资源字符串 **/private static void initAnimation(Activity activity) {Class<? extends Activity> clazz = activity.getClass();//获取该类信息Field[] fields=clazz.getDeclaredFields();//获致所有成员变更for (Field field:fields) {GT_Res.GT_Animation initView = field.getAnnotation(GT_Res.GT_Animation.class);if(initView!=null){int viewRes = initView.value();try {Animation animation = AnimationUtils.loadAnimation(activity, viewRes);field.setAccessible(true);field.set(activity,animation);} catch (Exception e) {e.printStackTrace();}}}}/** 注入 Dimen 资源字符串 **/private static void initDimen(Activity activity) {Class<? extends Activity> clazz = activity.getClass();//获取该类信息Field[] fields=clazz.getDeclaredFields();//获致所有成员变更for (Field field:fields) {GT_Res.GT_Dimen initView = field.getAnnotation(GT_Res.GT_Dimen.class);if(initView!=null){int viewRes = initView.value();try {float dimension = activity.getResources().getDimension(viewRes);field.setAccessible(true);field.set(activity,dimension);} catch (Exception e) {e.printStackTrace();}}}}/** 注入 Drawable 资源字符串 **/private static void initDrawable(Activity activity) {Class<? extends Activity> clazz = activity.getClass();//获取该类信息Field[] fields=clazz.getDeclaredFields();//获致所有成员变更for (Field field:fields) {GT_Res.GT_Drawable initView = field.getAnnotation(GT_Res.GT_Drawable.class);if(initView!=null){int viewRes = initView.value();try {Drawable drawable = activity.getResources().getDrawable(viewRes);field.setAccessible(true);field.set(activity,drawable);} catch (Exception e) {e.printStackTrace();}}}}/** 注入 Color 资源字符串 **/private static void initColor(Activity activity) {Class<? extends Activity> clazz = activity.getClass();//获取该类信息Field[] fields=clazz.getDeclaredFields();//获致所有成员变更for (Field field:fields) {GT_Res.GT_Color initView = field.getAnnotation(GT_Res.GT_Color.class);if(initView!=null){int viewRes = initView.value();try {int color = activity.getResources().getColor(viewRes);field.setAccessible(true);field.set(activity,color);} catch (Exception e) {e.printStackTrace();}}}}/** 注入 String 资源字符串 **/private static void initString(Activity activity) {Class<? extends Activity> clazz = activity.getClass();//获取该类信息Field[] fields=clazz.getDeclaredFields();//获致所有成员变更for (Field field:fields) {GT_Res.GT_String initView = field.getAnnotation(GT_Res.GT_String.class);if(initView!=null){int viewRes = initView.value();try {String string = activity.getResources().getString(viewRes);field.setAccessible(true);field.set(activity,string);} catch (Exception e) {e.printStackTrace();}}}}/*** 参数版* @param object*/private static void initObject(Object object){Class<? extends Object> clazz = object.getClass();//获取该类信息Field[] fields = clazz.getDeclaredFields();//获致所有成员变更for (Field field:fields) {GT_Object initView = field.getAnnotation(GT_Object.class);if(initView != null){//获取 完整的类路径String classPage = field.toString();String[] s = classPage.split(" ");classPage = s[1];//实例化一个对象Object object2 = null;try {object2 = Class.forName(classPage).newInstance();} catch (IllegalAccessException e) {e.printStackTrace();} catch (InstantiationException e) {e.printStackTrace();} catch (ClassNotFoundException e) {e.printStackTrace();}//获取参数的值类型String type = initView.type();String[] types = initView.types();//创建保存 参数类型的容器List<Object> valueList = new ArrayList<>();if(type.length() != 0){valueType(type,valueList,initView,0);//将当前的单个数据赋值到 listView 中}else if(types.length != 0){for(int i = 0; i < types.length; i++){valueType(types[i],valueList,initView,i);//将当前的多个数据赋值到 listView 中}}String function = initView.function();String[] functions = initView.functions();/*** 获取当前方法所有方法*/if(function.length() != 0 && valueList.size() != 0){functionValue(field,object2,function,valueList,0);//对相应的方法进行赋值}else if(functions.length != 0 && valueList.size() != 0){for(int i = 0; i < functions.length; i++){functionValue(field,object2,functions[i],valueList,i);//对相应的方法进行赋值}}//给注解下面的 成员变量注入值try {field.setAccessible(true);field.set(object,object2);} catch (IllegalAccessException e) {e.printStackTrace();}}}}private static void functionValue(Field field, Object object, String functionName, List<Object> valueList, int index){if(functionName.length() != 0 && valueList.size() != 0){Class<?> aClass = object.getClass();Method[] methods = aClass.getMethods();//获取当前类中所有方法for(int i = methods.length-1; i >= 0 ; i--){String name = methods[i].getName();if(name.equals(functionName)){try {Method method = getAllValueTypeMethod(valueList.get(index),functionName,aClass);method.setAccessible(true);field.setAccessible(true);method.invoke(object, valueList.get(index));} catch (Exception e) {GT.log_i("赋值报错");e.printStackTrace();}}}}}/*** 自获取当前传入数据的类型* @param data* @param functionName* @param aClass* @return*/private static Method getAllValueTypeMethod(Object data, String functionName, Class<?> aClass){Method method = null;Class<?> aClass1 = data.getClass();switch (aClass1.toString()){case "class java.lang.Byte":try {method = aClass.getMethod(functionName, byte.class);} catch (NoSuchMethodException e) {
// e.printStackTrace();}break;case "class java.lang.Short":try {method = aClass.getMethod(functionName, short.class);} catch (NoSuchMethodException e) {
// e.printStackTrace();}break;case "class java.lang.Integer":try {method = aClass.getMethod(functionName, int.class);} catch (NoSuchMethodException e) {
// e.printStackTrace();}break;case "class java.lang.Long":try {method = aClass.getMethod(functionName, long.class);} catch (NoSuchMethodException e) {
// e.printStackTrace();}break;case "class java.lang.Float":try {method = aClass.getMethod(functionName, float.class);} catch (NoSuchMethodException e) {
// e.printStackTrace();}break;case "class java.lang.Double":try {method = aClass.getMethod(functionName, double.class);} catch (NoSuchMethodException e) {
// e.printStackTrace();}break;case "class java.lang.Boolean":try {method = aClass.getMethod(functionName, boolean.class);} catch (NoSuchMethodException e) {
// e.printStackTrace();}break;case "class java.lang.Character":try {method = aClass.getMethod(functionName, char.class);} catch (NoSuchMethodException e) {
// e.printStackTrace();}break;case "class java.lang.String":try {method = aClass.getMethod(functionName, String.class);} catch (NoSuchMethodException e) {
// e.printStackTrace();}break;}return method;}/*** 给 listView 赋值* @param type* @param list* @param values*/private static void valueType(String type, List<Object> list, GT_Object values, int index){switch (type){/** 单个参数的赋值 **/case "byte":list.add(values.valueByte());break;case "short":list.add(values.valueShort());break;case "int":list.add(values.valueInt());break;case "long":list.add(values.valueLong());break;case "float":list.add(values.valueFloat());break;case "double":list.add(values.valueDouble());break;case "boolean":list.add(values.valueBoolean());break;case "char":list.add(values.valueChar());break;case "String":list.add(values.valueString());break;/** 多个参数的赋值 **/case "bytes":byte[] bytes = values.valueBytes();for(byte value:bytes){list.add(value);}break;case "shorts":short[] shorts = values.valueShorts();list.add(shorts[index]);break;case "ints":int[] ints = values.valueInts();list.add(ints[index]);break;case "longs":long[] longs = values.valueLongs();list.add(longs[index]);break;case "floats":float[] floats = values.valueFloats();list.add(floats[index]);break;case "doubles":double[] doubles = values.valueDoubles();list.add(doubles[index]);break;case "booleans":boolean[] booleans = values.valueBooleans();list.add(booleans[index]);break;case "chars":char[] chars = values.valueChars();list.add(chars[index]);break;case "Strings":String[] strings = values.valueStrings();list.add(strings[index]);break;}}/*** 注入 ContextView* @param activity*/private static void initActivity(Activity activity){Class<? extends Activity> mClass = activity.getClass();//获取该类信息GT_Activity contentView = mClass.getAnnotation(GT_Activity.class);//获取该类 ContextView 的注解类//如果有注解if(contentView != null){int viewId = contentView.value();//获取注解类参数try {Method method = mClass.getMethod("setContentView",int.class);//获取该方法的信息method.setAccessible(true);//获取该方法的访问权限method.invoke(activity,viewId);//调用该方法的,并设置该方法参数} catch (NoSuchMethodException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();}}}/***注入控件* @param activity*/private static void initView(Activity activity){Class<? extends Activity> clazz = activity.getClass();//获取该类信息Field[] fields=clazz.getDeclaredFields();//获致所有成员变更for (Field field:fields) {GT_View initView = field.getAnnotation(GT_View.class);if(initView!=null){int viewId=initView.value();try {Method method = clazz.getMethod("findViewById", int.class);method.setAccessible(true);field.setAccessible(true);Object object = method.invoke(activity, viewId);field.set(activity,object);} catch (Exception e) {e.printStackTrace();}}}}/*** 注入点击事件* @param activity*/private static void initClick(Activity activity){Class<? extends Activity> clazz = activity.getClass();Method[] methods= clazz.getMethods();//获取所有声明为公有的方法for (Method method:methods){//遍历所有公有方法Annotation[] annotations = method.getAnnotations();//获取该公有方法的所有注解for (Annotation annotation:annotations){//遍历所有注解Class<? extends Annotation> annotationType = annotation.annotationType();//获取具体的注解类OnClickEvent onClickEvent = annotationType.getAnnotation(OnClickEvent.class);//取出注解的onClickEvent注解if(onClickEvent!=null){//如果不为空try {Method valueMethod=annotationType.getDeclaredMethod("value");//获取注解InjectOnClick的value方法int[] viewIds= (int[]) valueMethod.invoke(annotation, (Object[]) null);//获取控件值Class<?> listenerType = onClickEvent.listenerType();//获取接口类型String listenerSetter = onClickEvent.listenerSetter();//获取set方法String methodName = onClickEvent.methodName();//获取接口需要实现的方法MyInvocationHandler handler = new MyInvocationHandler(activity);//自己实现的代码,负责调用handler.setMethodMap(methodName,method);//设置方法及设置方法Object object= Proxy.newProxyInstance(listenerType.getClassLoader(),new Class<?>[]{listenerType},handler);//创建动态代理对象类for (int viewId:viewIds){//遍历要设置监听的控件View view=activity.findViewById(viewId);//获取该控件Method m=view.getClass().getMethod(listenerSetter, listenerType);//获取方法m.invoke(view,object);//调用方法}} catch (Exception e) {e.printStackTrace();}}}}}//注解帮助类static class MyInvocationHandler implements InvocationHandler {private Object object;private Map<String, Method> methodMap = new HashMap<>(1);public MyInvocationHandler(Object object) {this.object = object;}public void setMethodMap(String name, Method method) {this.methodMap.put(name, method);}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {if (object != null) {String name = method.getName();method= this.methodMap.get(name);if (method != null) {return method.invoke(object, args);}}return null;}}}
一下子码这么多,我也是第一次写博客写这么多,我们休息一下,我们看个美景,缓缓眼睛疲劳:
接下来,我们就只欠东风了。
第三步:新建必要的文件:
LoginBean、Fragment_1、Fragment_2、Fragment_3
LoginBean:代码如下
public class LoginBean {private String username;private String password;private int age;public void setAge(int age) {this.age = age;}public LoginBean() {super();}public LoginBean(String username, String password, int age) {this.username = username;this.password = password;}public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}@Overridepublic String toString() {return "LoginBean{" +"username='" + username + '\'' +", password='" + password + '\'' +", age=" + age +'}';}}
Fragment_1:代码如下
public class Fragment_1 extends Fragment {private static final String TAG = "GT_";public static Fragment_1 newInstance() {Bundle args = new Bundle();Log.i(TAG,"Fragment_1 newInstance");Fragment_1 fragment = new Fragment_1();fragment.setArguments(args);return fragment;}public Fragment_1(){Log.i(TAG,"Fragment_1");}}
Fragment_2:代码如下
public class Fragment_2 extends Fragment {private static final String TAG = "GT_";public static Fragment_2 newInstance() {Bundle args = new Bundle();Log.i(TAG,"Fragment_2 newInstance");Fragment_2 fragment = new Fragment_2();fragment.setArguments(args);return fragment;}public Fragment_2(){Log.i(TAG,"Fragment_2");}}
Fragment_3:代码如下
public class Fragment_3 extends Fragment {private static final String TAG = "GT_";public static Fragment_3 newInstance() {Bundle args = new Bundle();Log.i(TAG,"Fragment_3 newInstance");Fragment_3 fragment = new Fragment_3();fragment.setArguments(args);return fragment;}public Fragment_3(){Log.i(TAG,"Fragment_3");}}
第四步:添加测试资源文件
alpha.xml 代码:
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"><!-- alpha 设置透明度fromAlpha : 起始点的透明度toAlpha : 结束点的透明度duration : 设置透明度渐变的时间 已毫秒为单位repeatCount: 设置重复次数repeatMode: reverse(反向) | restart(重新开始) 设置重复方式--><alphaandroid:fromAlpha="0.5"android:toAlpha="1"android:duration="2000"/></set>
activity_main.xml 代码:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayoutxmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivity"><TextViewandroid:id="@+id/ioc_tv"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="Hello World!"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintLeft_toLeftOf="parent"app:layout_constraintRight_toRightOf="parent"app:layout_constraintTop_toTopOf="parent" /><Buttonandroid:id="@+id/ioc_btn"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="单击测试"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toTopOf="parent"app:layout_constraintVertical_bias="0.603" /><LinearLayoutandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:orientation="vertical"app:layout_constraintBottom_toTopOf="@+id/ioc_tv"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toTopOf="parent"><Buttonandroid:id="@+id/ioc_btn01"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="按钮1" /><Buttonandroid:id="@+id/ioc_btn02"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="按钮2" /><Buttonandroid:id="@+id/ioc_btn03"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="按钮3" /></LinearLayout></androidx.constraintlayout.widget.ConstraintLayout>
arrays.xml 代码:
<?xml version="1.0" encoding="utf-8"?>
<resources><!--定义字符串元素--><string-array name="ctype"><item>全部</item><item>电影</item><item>娱乐</item><item>图书</item><item>运动</item></string-array><!--定义整数类型数组--><integer-array name="textInt"><item>1</item><item>2</item><item>3</item></integer-array></resources>
colors.xml 代码:
<?xml version="1.0" encoding="utf-8"?>
<resources><color name="colorPrimary">#008577</color><color name="colorPrimaryDark">#00574B</color><color name="colorAccent">#D81B60</color><color name="colorTest">#FFE700</color>
</resources>
dimens.xml 代码:
<?xml version="1.0" encoding="utf-8"?>
<resources><!--定义尺寸资源--><dimen name="tv_size">10sp</dimen></resources>
strings.xml 代码:
<resources><string name="app_name">Butter Knife(小刀注解)</string><string name="StringTest">测试数据</string>
</resources>
最后步:添加测试代码
MainActivity.java 代码:
@GT_Activity(R.layout.activity_main)
public class MainActivity extends AppCompatActivity {@GT_View(R.id.ioc_tv)private TextView tv;@GT_View(R.id.ioc_btn)private Button btn;@GT_Object(valueString = "1079",valueInt = 21,types = {GT_Object.TYPE.STRING, GT_Object.TYPE.INT}, functions = {"setUsername","setAge"})private LoginBean loginBean;@GT_Res.GT_String(R.string.StringTest)private String data;@GT_Res.GT_Color(R.color.colorTest)private int MyColor;@GT_Res.GT_Drawable(R.drawable.ic_launcher_background)private Drawable btnBG;@GT_Res.GT_Dimen(R.dimen.tv_size)private float TextSize;@GT_Res.GT_Animation(R.anim.alpha)private Animation animation;@GT_Res.GT_StringArray(R.array.ctype)private String[] strArray;@GT_Res.GT_IntArray(R.array.textInt)private int[] intArray;@GT_Res.GT_Layout(R.layout.activity_main)private View layout;private static final String TAG = "GT_";protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);GT_Util.initAll(this);//绑定 ActivityGT.log_e( "onCreate: tv = " + tv + " btn:" + btn);btn.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {Log.i(TAG,"loginBean: " + loginBean);Log.i(TAG,"data: " + data);Log.i(TAG,"color: " + MyColor);Log.i(TAG,"Drawable: " + btnBG);Log.i(TAG,"TextSize: " + TextSize);Log.i(TAG,"animation: " + animation);Log.i(TAG,"strArray: " + strArray);Log.i(TAG,"intArray: " + intArray);Log.i(TAG,"layout: " + layout);tv.setText("实现成功!");btn.setTextColor(MyColor);btn.setTextSize(TextSize);btn.setBackgroundDrawable(btnBG);btn.startAnimation(animation);}});}@GT_Click({R.id.ioc_btn01,R.id.ioc_btn02,R.id.ioc_btn03})public void testBtnOnCLick(View view){switch (view.getId()){case R.id.ioc_btn01:Log.i(TAG,"单击 1 号" );break;case R.id.ioc_btn02:Log.i(TAG,"单击 2 号" );break;case R.id.ioc_btn03:Log.i(TAG,"单击 3 号" );break;}}}
终于完成了所有代码的编写,现在我们来看看你花这10分钟到底值不值吧。٩(๑>◡<๑)۶
运行效果图:
打印日志:
08-30 12:11:33.918 3723-3723/com.gsls.myapplication E/GT_e: ------- onCreate: tv = androidx.appcompat.widget.AppCompatTextView{5552d29 V.ED.... ......ID 0,0-0,0 #7f08004d app:id/ioc_tv} btn:androidx.appcompat.widget.AppCompatButton{fbce8ae VFED..C. ......I. 0,0-0,0 #7f080049 app:id/ioc_btn}
08-30 12:11:41.841 3723-3723/com.gsls.myapplication I/GT_: 单击 1 号
08-30 12:11:42.408 3723-3723/com.gsls.myapplication I/GT_: 单击 2 号
08-30 12:11:43.001 3723-3723/com.gsls.myapplication I/GT_: 单击 3 号
08-30 12:11:44.255 3723-3723/com.gsls.myapplication I/GT_: loginBean: LoginBean{username='1079', password='null', age=21}
08-30 12:11:44.255 3723-3723/com.gsls.myapplication I/GT_: data: 测试数据
08-30 12:11:44.255 3723-3723/com.gsls.myapplication I/GT_: color: -6400
08-30 12:11:44.255 3723-3723/com.gsls.myapplication I/GT_: Drawable: android.graphics.drawable.VectorDrawable@2280d25b
08-30 12:11:44.255 3723-3723/com.gsls.myapplication I/GT_: TextSize: 10.0
08-30 12:11:44.255 3723-3723/com.gsls.myapplication I/GT_: animation: android.view.animation.AnimationSet@3e537af8
08-30 12:11:44.255 3723-3723/com.gsls.myapplication I/GT_: strArray: [Ljava.lang.String;@cd31bd1
08-30 12:11:44.255 3723-3723/com.gsls.myapplication I/GT_: intArray: [I@1d02b636
08-30 12:11:44.255 3723-3723/com.gsls.myapplication I/GT_: layout: androidx.constraintlayout.widget.ConstraintLayout{11703937 V.E..... ......I. 0,0-0,0}
08-30 12:11:45.909 3723-3723/com.gsls.myapplication I/GT_: loginBean: LoginBean{username='1079', password='null', age=21}
08-30 12:11:45.909 3723-3723/com.gsls.myapplication I/GT_: data: 测试数据
08-30 12:11:45.909 3723-3723/com.gsls.myapplication I/GT_: color: -6400
08-30 12:11:45.909 3723-3723/com.gsls.myapplication I/GT_: Drawable: android.graphics.drawable.VectorDrawable@2280d25b
08-30 12:11:45.909 3723-3723/com.gsls.myapplication I/GT_: TextSize: 10.0
08-30 12:11:45.909 3723-3723/com.gsls.myapplication I/GT_: animation: android.view.animation.AnimationSet@3e537af8
08-30 12:11:45.909 3723-3723/com.gsls.myapplication I/GT_: strArray: [Ljava.lang.String;@cd31bd1
08-30 12:11:45.909 3723-3723/com.gsls.myapplication I/GT_: intArray: [I@1d02b636
08-30 12:11:45.909 3723-3723/com.gsls.myapplication I/GT_: layout: androidx.constraintlayout.widget.ConstraintLayout{11703937 V.E..... ......I. 0,0-0,0}
总结:看我这么辛苦。 点个关注呗<(▰˘◡˘▰)>
关注博主最新发布库:https://github.com/1079374315/GT
本篇文章源码地址:github地址:GitHub - 1079374315/GT_IOC: 教你10分钟手敲 Butter Knife(小刀注解)