一、基础注解
1、完成setContentView()的工作
1.1 创建注解@setContentView
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface setContentView {
int value();
}
1.2 反射完成setContentView()调用
private static void injectContentViewLayout(Activity activity) {
Class<? extends Activity> aClass = activity.getClass();
// 获取activity上的setContentView注解
setContentView annotation = aClass.getAnnotation(setContentView.class);
if (annotation != null) {
try {
// 反射获取activity的setContentView方法。第一个参数是方法名,第二个参数是方法的参数
Method classMethod2 = aClass.getMethod("setContentView", int.class);
// 执行setContentView方法。第一个参数是对象bean,第二个参数是方法的参数
classMethod2.invoke(activity, annotation.value());
} catch (Exception e) {
e.printStackTrace();
}
}
}
1.3 添加注解@setContentView
@setContentView(R.layout.activity_main)
public class MainActivity extends AppCompatActivity
2、完成findViewById()的工作
2.1 创建注解@InjectView
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@interface InjectView {
int value();
}
2.2 反射完成findViewById()调用
private static void injectViewLayout(Activity activity) {
Class<? extends Activity> aClass = activity.getClass();
Field[] declaredFields = aClass.getDeclaredFields();
try {
Method classMethod = aClass.getMethod("findViewById", int.class);
for (Field declaredField : declaredFields) {
declaredField.setAccessible(true);
InjectView annotation = declaredField.getAnnotation(InjectView.class);
if (annotation != null) {
Object invoke = classMethod.invoke(activity, annotation.value());
declaredField.set(activity, invoke);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
2.3 添加注解@InjectView
@InjectView(R.id.tv1)
private TextView tv1;
3、完成setOnClickListener()的工作
3.1 创建注解@ViewClick
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@interface ViewClick {
int value();
}
3.2 反射完成setOnClickListener()调用
private static void injectViewClick(final Activity activity) {
Class<? extends Activity> aClass = activity.getClass();
Method classMethod = null;
try {
// 先找到findViewById()方法
classMethod = aClass.getMethod("findViewById", int.class);
// 获取到activity的所有方法。getDeclaredMethods包括私有。
Method[] declaredMethods = aClass.getDeclaredMethods();
for (final Method declaredMethod : declaredMethods) {
// 遍历所有方法,找到添加@ViewClick注解的方法。
ViewClick annotation = declaredMethod.getAnnotation(ViewClick.class);
if (annotation != null) {
// 获取到@ViewClick注解中的viewId
int value = annotation.value();
// 反射执行findViewById()
View view = (View) classMethod.invoke(activity, value);
// 找到view后,设置监听。执行添加@ViewClick注解的方法。
view.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
try {
declaredMethod.invoke(activity);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
3.3 添加注解@ViewClick
@ViewClick(R.id.bt1)
public void bt1Click() {
Log.e(TAG, "bt1Click: 被点击了");
}
二、通用注解
如果后期又添加了setOnLongClickListener()方法,那我们得重写一遍。那有什么办法可以一劳永逸呢?
还是以setOnClickListener为例,我们可以将之前的代码分成三个要素组成:setOnClickListener()、OnClickListener.class、onClick()
bt2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
}
});
1、定义base注解
@Target(ElementType.ANNOTATION_TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface BaseListener {
String listenerMethodName();
// listerClass = ""
Class listerClass();
String listenerCallback();
}
2、定义子注解
2.1 定义@ViewClickListener注解,完成setOnClickListener()工作
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@BaseListener(listenerMethodName = "setOnClickListener" // 监听
,listerClass = View.OnClickListener.class // 接口
,listenerCallback = "onClick") // 接口回调方法
@interface ViewClickListener {
int value();
}
2.2 定义@ViewLongClickListener注解,完成setOnLongClickListener()工作
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@BaseListener(listenerMethodName = "setOnLongClickListener"
,listerClass = View.OnLongClickListener.class
,listenerCallback = "onLongClick")
@interface ViewLongClickListener {
int value();
}
3、反射完成监听工作
private static void injectViewListener(final Activity activity) {
Class<? extends Activity> activityClass = activity.getClass();
Method[] declaredMethods = activityClass.getDeclaredMethods();
for (final Method declaredMethod : declaredMethods) {
declaredMethod.setAccessible(true);
// 找到该方法上所有的注解
Annotation[] annotations = declaredMethod.getAnnotations();
// 遍历注解
for (Annotation annotation : annotations) {
// 找注解上的注解,也就是我们前面的base注解
Class<? extends Annotation> aClass1 = annotation.annotationType();
BaseListener baseListenerAnnotation = aClass1.getAnnotation(BaseListener.class);
// 找到了base注解,获取值。
if (baseListenerAnnotation != null) {
String methodName = baseListenerAnnotation.listenerMethodName();
Class listerClass = baseListenerAnnotation.listerClass();
final String listenerCallback = baseListenerAnnotation.listenerCallback();
// 先获取到@ViewClickListener上的值。通过反射吧
try {
// 获取到activity中注解的值,也就是viewId。但无法像前面那样直接获取。需要调用value方法获取。
Method valueMethod = annotation.getClass().getDeclaredMethod("value");
valueMethod.setAccessible(true);
// 找到viewId。
int viewId = (int) valueMethod.invoke(annotation);
// 找到了viewId后,执行findViewById
Method classMethod = activityClass.getMethod("findViewById", int.class);
View invokeView = (View) classMethod.invoke(activity, viewId);
// 获取到view的方法
Method doClassMethod = invokeView.getClass().getMethod(methodName, listerClass);
// 这里需要用到动态代理了
Object proxyInstance = Proxy.newProxyInstance(listerClass.getClassLoader()
, new Class[]{listerClass}
, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 当监听回调返回,会执行到这里
if (TextUtils.equals(listenerCallback, method.getName())) {
// 执行activity中添加注解的方法。
return declaredMethod.invoke(activity, null);
}
return null;
}
});
// 执行view的setOnClickListener()方法
doClassMethod.invoke(invokeView, proxyInstance);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
4、activity中引用
@ViewClickListener(R.id.bt1)
public void bt1Click() {
Log.e(TAG, "bt1Click: 被点击了");
}
@ViewLongClickListener(R.id.bt1)
public boolean bt1Click2() {
Log.e(TAG, "bt1Click: 被长按了.........");
return true;
}
@ViewClickListener(R.id.bt2)
public void bt1Click3() {
Log.e(TAG, "bt2Click: 被点击了");
}
网友评论