手写注入框架-ButterKnife
2020-10-15 本文已影响0人
有腹肌的豌豆Z
定义Annotation
BindView
@Retention(RetentionPolicy.RUNTIME)//CLASS 编译时注解 RUNTIME运行时注解 SOURCE 源码注解
@Target(ElementType.FIELD)//注解作用范围:FIELD 属性 METHOD方法 TYPE 放在类上
public @interface BindView { //@interface则是表明这个类是一个注解
int value(); //表示@ViewById() 注解时,括号里面的编写的为int类型的值
}
ContentView
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface ContentView {
int value();
}
OnClick
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface OnClick {
int[] value();
}
OnLongClick
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface OnLongClick {
int[] value();
}
ButterKnife
/**
* 手写 注解框架
*/
public class ButterKnife {
/**
* 注入
*/
public static void inject(Activity activity) {
injectContentView(activity);
findViewById(activity);
setOnClickListener(activity);
setOnLongClickListener(activity);
}
/**
* 注入主布局文件
*/
private static void injectContentView(Activity activity) {
Class<? extends Activity> clazz = activity.getClass();
// 查询类上是否存在ContentView注解
ContentView contentView = clazz.getAnnotation(ContentView.class);
if (contentView != null) {// 存在
int contentViewLayoutId = contentView.value();
try {
Method method = clazz.getMethod("setContentView", int.class);
method.setAccessible(true);
method.invoke(activity, contentViewLayoutId);
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* 声明 View
*/
private static void findViewById(Activity activity) {
//获取Activity的class
Class<? extends Activity> clazz = activity.getClass();
//获取该类中的所有声明的属性
Field[] declaredFields = clazz.getDeclaredFields();
//遍历所有属性,找到用@ViewById注解了的属性
for (int i = 0; i < declaredFields.length; i++) {
Field field = declaredFields[i];
//获取属性上的注解对象
//@ViewById(R.id.textView) R.id.textView--value
//TextView textView;//属性
BindView annotation = field.getAnnotation(BindView.class);
if (annotation != null) {
int viewId = annotation.value();
// TODO 是不是很熟悉
View view = activity.findViewById(viewId);
try {
//私有属性也可以动态注入(不写该句代码,private声明的属性会报异常)
field.setAccessible(true);
field.set(activity, view);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
/**
* 处理OnClick注解
*/
private static void setOnClickListener(final Activity activity) {
// findViewById setOnClick
// 1.获取该Activity的所有方法
Class<?> clazz = activity.getClass();
//Method[] methods = clazz.getDeclaredMethods();
// 2.遍历方法获取所有的值
//for (final Method method:methods){
// 2.1 获取OnClick注解
//OnClickView onClick = method.getAnnotation(OnClickView.class);
try {
final Method method = clazz.getMethod("onClick", View.class);
OnClick onClick = method.getAnnotation(OnClick.class);
// 2.2 该方法上是否有OnClick注解
if (onClick != null) {
// 2.3 获取OnClick里面所有的值
int[] viewIds = onClick.value();// @OnClick({R.id.text_view,R.id.button})
// 2.4 先findViewById , setOnclick
for (int viewId : viewIds) {
// 先findViewById
final View view = activity.findViewById(viewId);
// 后设置setOnclick
view.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 首先需要判断 方法是否需要检测网络
// 3.反射调用原来配置了OnClick的方法
method.setAccessible(true);// 私有的方法
try {
method.invoke(activity);// 调用无参的方法
} catch (Exception e) {
e.printStackTrace();
try {
method.invoke(activity, view);// 调用有参的方法 view 代表当前点击的View
} catch (Exception e1) {
e1.printStackTrace();
}
}
}
});
}
// }
}
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
/**
* 处理onLongClick注解
*/
private static void setOnLongClickListener(final Activity activity) {
Class<?> clazz = activity.getClass();
try {
final Method method = clazz.getMethod("onLongClick", View.class);
OnLongClick onClick = method.getAnnotation(OnLongClick.class);
if (onClick != null) {
int[] viewIds = onClick.value();
for (int viewId : viewIds) {
final View view = activity.findViewById(viewId);
view.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
method.setAccessible(true);
try {
method.invoke(activity);
} catch (Exception e) {
e.printStackTrace();
try {
method.invoke(activity, view);
} catch (Exception e1) {
e1.printStackTrace();
}
}
return true;
}
});
}
}
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
}
使用
@ContentView(R.layout.activity_main)
public class MainActivity extends AppCompatActivity {
@BindView(R.id.textView)
TextView textView;
@OnClick({R.id.button}) //可注入多个view
public void onClick(View view) {
switch (view.getId()) {
case R.id.button:
textView.setText("我是手写ButterKnife框架");
break;
default:
Log.e("MainActivity", "view not found");
break;
}
}
@OnLongClick(R.id.button)
public void onLongClick(View view) {
Toast.makeText(this, "长按", Toast.LENGTH_SHORT).show();
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//setContentView(R.layout.activity_main);
// 注入 当前 Activity
ButterKnife.inject(this);
}
}