比如我们在Activity里面不想通过
view.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
}
});
view.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
return false;
}
});
现在只我们只需要定义一个OnClick注解接口就可以实现
先来分析一下上面二个方法有什么共同点
1):方法名:(setOnClickListener,setOnLongClickListener)
2):方法参数:(View.OnClickListener,View.OnLongClickListener),二个接口
3):执行方法:(onClick,onLongClick)
有了这些共同点就好办,
第一: 我们定义一个事件注解 EventBase
@Target(ElementType.ANNOTATION_TYPE)//放在注解之上
@Retention(RetentionPolicy.RUNTIME)
public @interface EventBase {
String listenerSetter();// 监听的方法名 比如: setOnClickListener()
Class<?> listenerType(); // 获取到需要监听的类 比如: View.OnClickListener
String callBackListener();//比如 onClick()
}
第二: 我们再来定义一个OnClick注解
@Target(ElementType.METHOD)//注解在方法之上
@Retention(RetentionPolicy.RUNTIME) //运行时执行
@EventBase(listenerSetter = "setOnClickListener", listenerType = View.OnClickListener.class, callBackListener = "onClick") //上面写的注解类,注解在注解之上的
public @interface OnClick {
int[] value();
}
第三: 接下来我们就来写一些自动生成点击事件了
定义方法
private static void injectEvents(Activity activity) {} //activity
public static void injectEvents(Fragment fragment,View contentView){} //fragment
二个基本实现一样,就以activity为例
private static void injectEvents(Activity activity) {
Class<? extends Activity> clazz = activity.getClass();//获取到类
Method[] methods = clazz.getDeclaredMethods();//获取到该activity类下所有的公有或者私有的方法,不包括父类
for (Method method : methods) {//对方法一个一个遍历
Annotation[] annotations = method.getAnnotations();//获取到方法上所有的注解,因为有可能有多个注解,比如上注解上加注解
for (Annotation annotation : annotations) {//遍历获取到的注解集合
Class<? extends Annotation> annotationType = annotation.annotationType();//获取到注解上的类型
if (annotationType != null) {
EventBase eventBase = annotationType.getAnnotation(EventBase.class);//获取到注解上的注解,如果是我们自己写的@EventBase的时候往下走,不是则下一循环
if (eventBase != null) {
//获取到了注解上的注解的一些参数
String listenerSetter = eventBase.listenerSetter(); // setOnClickListener
String callBackListener = eventBase.callBackListener(); // onClick
Class<?> listenerType = eventBase.listenerType();// interface android.view.View$OnClickListener
//接下来就是要实现我们怎么动态代理view里面的点击事件了
//创建一个带有目标activity对象的代理handler 将我们对象里面的method 方法进行添加
ListenerInvocationHandler handler = new ListenerInvocationHandler(activity);
handler.addMethod(callBackListener, method);
//这句代码是获取到了View.OnclickListener对象
Object listener = Proxy.newProxyInstance(listenerType.getClassLoader(), new Class[]{listenerType}, handler);//比如每当我们调用了listenerType里面的方法时,就会进入到handler类里的invoke方法里.
try {
Method valueMethod = annotationType.getDeclaredMethod("value");//annotationType就是我们定义的@OnClick注解接口 这名话的意思就是获取到接口里面的value方法
int[] viewIds = (int[]) valueMethod.invoke(annotation);//通过反射获取到的valueMethod方法来获取到返回的数据,anotation就是我们的注解类的实例
for (int viewId : viewIds) {
View view = activity.findViewById(viewId);
Method m = view.getClass().getMethod(listenerSetter, listenerType);//获取到View.setOnclickListener()方法
m.invoke(view, listener);//执行的是view.setOnClickListener(new View.OnClickListener(){ onClick();})
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
}
//动态代理其实就是实现了InvocationHandler接口,并实现里面的invoke方法来实现的
public class ListenerInvocationHandler implements InvocationHandler {
private Object target;
private HashMap<String, Method> methodMethod = new HashMap();
public ListenerInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (target != null) {
//获取需要拦截的方法
String methodName = method.getName();
Method targetMethod = methodMethod.get(methodName);
if (targetMethod != null) {
return targetMethod.invoke(target, args);
}
}
return null;
}
/**
* @param methodName 方法名称
* @param method 需要添加的方法
*/
public void addMethod(String methodName, Method method) {
methodMethod.put(methodName, method);
}
}
最后写法也是非常的简单
首先在onCreate方法里面执行上面方法
@OnClick({R.id.btn, R.id.tv})
public void onClick(View v) {
Toast.makeText(MainActivity.this, "R.id.btn", Toast.LENGTH_SHORT).show();
}
然后就没有然后