今天自己学者写个注解框架,参考butterknife,在实现点击事件的时候遇到一个问题。
java代码:
Class<?> clazz = object.getClass();
Method[] methods = clazz.getDeclaredMethods();
for (Method method : methods) {
Annotation[] annotations = method.getAnnotations();
for (Annotation annotation : annotations) {
Class<? extends Annotation> annotationType = annotation.annotationType();
InjectEvent injectEvent = annotationType.getAnnotation(InjectEvent.class);
String listenerSetter = injectEvent.listenerSetter();
Class<?> listenerType = injectEvent.listenerType();
String callBackMethod = injectEvent.callBackMethod();
try {
Object listener = Proxy.newProxyInstance(listenerType.getClassLoader(),
new Class[]{listenerType}, new ListenerHandler(object, method));
Method valueMethod = annotationType.getDeclaredMethod("value");
int[] ids = (int[]) valueMethod.invoke(annotation);
for (int id : ids) {
Method findViewById = clazz.getMethod("findViewById", int.class);
View view = (View) findViewById.invoke(object, id);
Method setterMethod = view.getClass().getMethod(listenerSetter, listenerType);
setterMethod.invoke(view, listener);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
直接用转换工具转换:
嗯?啥情况。
翻看源码得知,kotlin是通过 annotationClass 来获取 annotationType 的
so,改成了这样~
// 事件注入
private fun injectEvent(obj: Any) {
val clazz = obj.javaClass
// 获取所有方法
val methods = clazz.declaredMethods
methods.forEach { method ->
// 获取方法上的所有注解
val annot = method.annotations
annot.forEach { annotation ->
// 根据annotationType获取injectEvent
val annotationType = annotation.annotationClass.java
val injectEvent = annotationType.getAnnotation(InjectEvent::class.java)
injectEvent?.let {
// 获取传递的参数
val listenerSetter = it.listenerSetter
val listenerType = it.listenerType.java
val callBackMethod = it.callBackMethod
// 动态代理注入要执行的方法(onClilc还是onLongClick或者其他的)
val listener = Proxy.newProxyInstance(
listenerType.classLoader,
arrayOf(listenerType),
ListenerHandler(obj, method)
)
// 获取注解的value方法并获取其值
val valueMethod = annotationType.getDeclaredMethod("value")
val ids = valueMethod.invoke(annotation) as IntArray
//遍历id获取具体的控件,并为其设置相应的触摸事件
ids.forEach { mId ->
val findViewById = clazz.getMethod("findViewById", Int::class.java)
val view = findViewById.invoke(obj, mId) as View
val setterMethod = view.javaClass.getMethod(listenerSetter, listenerType)
setterMethod.invoke(view, listener)
}
}
}
}
}
搞定~~~