教你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("卡哇伊");//使用组件}}

在实际项目中有什么好处呢?

Butter Knife(小刀注解)优点:

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(小刀注解)

Android——教你10分钟手敲 Butter Knife(小刀注解)相关推荐

  1. 手把手教你10分钟做一个音乐播放器

    一.话不多,先看效果: 视频B站效果演示地址~  (大佬勿入,大佬勿入,大佬勿入)这是个单页面音乐播放器,只用到了 html+css 与很基础的vue语法,所以适合初学者,看一看10分钟就会了~ 这个 ...

  2. 电脑忘记开机密码怎么办?教你10分钟搞定~

    我们时常会忘记自己电脑的开机密码,但是因为电脑中有很多重要的东西,不能格式化,网上搜了很多方法都不详细也不管用.现在教你十分钟修改密码. 写一篇文章记录这个过程,为自己多学习一个技能,也为了能帮助更多 ...

  3. 超详细教你10分钟搭建一个高端的B2B2C模式的综合性商城|含来客推V3源码下载

    需要用到服务器(云主机,虚拟空间),域名,源码 1. 服务器可以理解成一台电脑主机,用于处理存储计算传输等用途. 2. 域名比如你想访问一个网站是src1024.com这就是域名,如果你想回家 首先要 ...

  4. 《教你10分钟制作3D网游》视频吐槽

    源自GAMERES社区的MGE引擎(也即神秘游戏引擎),近期曝光了第一份制作游戏的带演示视频,透过视频我们发现,这不仅是一份演示或教程,更是一个略带心酸的故事. 视频刚开始,在悲伤的气氛下介绍了作者从 ...

  5. 很多小伙伴不太了解ORM框架的底层原理,这不,冰河带你10分钟手撸一个极简版ORM框架(赶快收藏吧)

    大家好,我是冰河~~ 最近很多小伙伴对ORM框架的实现很感兴趣,不少读者在冰河的微信上问:冰河,你知道ORM框架是如何实现的吗?比如像MyBatis和Hibernate这种ORM框架,它们是如何实现的 ...

  6. 10分钟手撸极简版ORM框架!

    最近很多小伙伴对ORM框架的实现很感兴趣,不少读者在冰河的微信上问:冰河,你知道ORM框架是如何实现的吗?比如像MyBatis和Hibernte这种ORM框架,它们是如何实现的呢? 为了能够让小伙伴们 ...

  7. 教你10分钟对接人大金仓EF Core 6.x

    [导读]目前.NET Core中据我了解到除了官方的EF Core外,还用的比较多的ORM框架(恕我孤陋寡闻哈,可能还有别的)有FreeSql.SqlSugar(排名不分先后). FreeSql和Sq ...

  8. 教你10分钟内在Windows上完成Rails开发环境的安装和配置

    原文:http://www.cnblogs.com/tambor/archive/2011/12/25/rails_anzhuang_railsinstaller.html 一般来说,Windows开 ...

  9. Android进阶: 10分钟实现NDK-JNI 开发教程

    项目简介 JNI:Java Native Interface(Java 本地编程接口),一套编程规范,它提供了若干的 API 实现了 Java 和其他语言的通信(主要是 C/C++).Java 可以通 ...

最新文章

  1. 实现800*600,1024*768两套分辨率方案
  2. 字符编码的知识(二)
  3. hdu 2553 N皇后问题【dfs】
  4. Qt文档阅读笔记-Broadcast Receiver Example解析
  5. amqp协议 面试_分布式消息中间件-RabbitMQ面试题(必问)
  6. java登陆session用法_Java web 登录 使用shiro和基于session的方式有何不同?
  7. String str = new String(abc)创建了几个对象?结合源码解析
  8. 无法访问udemy.com怎么办?
  9. 无锁并发和无等待并发的对比分析
  10. java xcap_java实现发布订阅
  11. 40个使用HDR的超棒夜景摄影照片展示
  12. 你如何理解软件测试?
  13. 卸载360天擎企业版
  14. python语句用什么隔开_在python中使用字典时用什么隔开
  15. outlook qr码在哪里_条码生成软件如何批量生成DPM码
  16. 三星在中国一面撤资,一面增资是为何?
  17. mysql免安装 默认密码_mysql5.17免安装的初始密码和重新设置密码
  18. 华为手机灭屏也能看时间吗?很多技巧你不知道,2分钟就能学会
  19. hdu 4302 Holedox Eating(优先队列)
  20. day2学python 数据类型+深浅拷贝+循环

热门文章

  1. 【OSTEP】分页: 快速地址转换(TLB) | TLB命中处理 | ASID 与页共享 | TLB替换策略: LRU策略与随机策略 | Culler定律
  2. 强化你的Cobalt strike之Cortana
  3. 跨专业考研必须要了解的5个常识!
  4. spaceclaim脚本(线生成面体)
  5. 页游与端游合体 微端网游或成为行业风向标
  6. springmvc拦截器 绝对路径
  7. 17届技术报告|国防科技大学-多车一师
  8. c语言常用数学函数大全查询,C语言数学函数 C语言中全部可用的数学函数有哪些?...
  9. 提交 AjaxPro加载的速度
  10. 教会舍友玩 Git (再也不用担心他的学习)