反射
-
什么是反射? 反射:是一种机制,利用该机制可以在程序运行过程中对类进行解剖并操作类中的方法,属性,构造方法等成员。
-
主要是指程序可以访问,检测和修改它本身状态或行为的一种能力,并能根据自身行为的状态和结果,调整或修改应用所描述行为的状态和相关的语义。
-
反射是java中一种强大的工具,能够很方便的创建灵活的代码,这些代码可以再运行时装配,无需在组件之间进行源代码链接。但是反射使用不当会成本很高
-
反射的调用:创建对象Constructor:newInstance()、执行方法Method:invoke()、设置及获取属性Filed: set(), get()
常用方法:
getDeclaredFields() : 获得class的成员变量
getDeclaredMethods() :获得class的成员方法
getDeclaredConstructors() :获得class的构造函数
...等等一系列方法
通过反射的方式,运行时动态获取注解信息。如下Demo
Demo
通过自定义注解+反射实现牛油刀功能
自定义注解:
@BindView
@Target(ElementType.FIELD) // 作用在属性之上
@Retention(RetentionPolicy.RUNTIME) // 运行时
public @interface BindView {
/** View Id */
@IdRes int value() default -1;
}
@OnClick
@Target(ElementType.METHOD) // 作用在属性之上
@Retention(RetentionPolicy.RUNTIME) // 运行时
public @interface OnClick {
/** View Ids */
@IdRes int[] value();
}
处理类 Reflex
public class Reflex {
/** 绑定 */
public static void bind(Activity activity) {
// 判断传入的Activity是否为空,为空进行过滤不处理
if (activity == null) return;
// 查找所有使用了自定义 @BindView 注解的属性并赋值
assignmentFields(activity);
// 查找所有使用了自定义 @OnClick 注解的方法,使用动态代理实现点击事件
dynamicProxyMethod(activity);
}
/** 查找所有使用了自定义 @BindView 注解的属性并赋值 */
private static void assignmentFields(Activity activity) {
// 获取class对象
Class<? extends Activity> clazz = activity.getClass();
// 获取所有成员属性
Field[] fields = clazz.getDeclaredFields();
// 遍历所有成员属性
for (Field field : fields) {
// 判断该属性是否使用了自定义注解且为View
if (field.isAnnotationPresent(BindView.class)) {
// 获取当前属性上的注解对象
BindView annotation = field.getAnnotation(BindView.class);
// 获取注解的值
int idRes = annotation.value();
// 判断注解值
if (idRes != -1) {
try {
// 设置属性可见
field.setAccessible(true);
// 赋值
field.set(activity, activity.findViewById(idRes));
} catch (IllegalAccessException e) {
throw new RuntimeException(clazz.getName() + "的" + field.getName() + "注解异常!");
}
}
}
}
}
/** 查找所有使用了自定义 @OnClick 注解的方法,使用动态代理实现点击事件 */
private static void dynamicProxyMethod(final Activity activity) {
// 获取class对象
Class<? extends Activity> clazz = activity.getClass();
// 获取所有的方法
Method[] methods = clazz.getDeclaredMethods();
// 遍历所有的方法
for (final Method method : methods) {
// 判断该方法是否使用了自定义注解
if (method.isAnnotationPresent(OnClick.class)) {
// 获取当前方法上的注解对象
OnClick annotation = method.getAnnotation(OnClick.class);
// 获取注解的值
int[] values = annotation.value();
// 遍历所有的值
for (int value : values) {
// 根据ID获取View
View view = activity.findViewById(value);
// 设置方法可见
method.setAccessible(true);
// 设置View的点击事件
view.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
try {
method.invoke(activity, view);
} catch (Exception e) {
throw new RuntimeException(activity.getClass().getName() + "的" + method.getName() + "注解异常!");
}
}
});
}
}
}
}
}
MainActivity
public class MainActivity extends AppCompatActivity {
@BindView(R.id.textView)
TextView textView;
@BindView(R.id.textView1)
TextView textView1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 使用自定义反射工具,动态获取信息并进行业务处理
Reflex.bind(this);
}
@OnClick({R.id.textView, R.id.textView1})
public void onClick(View view) {
switch (view.getId()) {
case R.id.textView:
Toast.makeText(this, "你好呀!", Toast.LENGTH_SHORT).show();
textView.setText("你好呀");
break;
case R.id.textView1:
Toast.makeText(this, "嗯,我很好。", Toast.LENGTH_SHORT).show();
textView1.setText("嗯,我很好。");
break;
default:
break;
}
}
}
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">
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TextView1"
app:layout_constraintBottom_toTopOf="@+id/textView1"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_chainStyle="packed" />
<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="50dp"
android:text="TextView2"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView" />
</androidx.constraintlayout.widget.ConstraintLayout>
网友评论