Android-自定义注解-Java动态代理(Proxy)-动态代理实现
我们一路从java注解基础,元注解、自定义注解、反射、代理【动态代理】模式一路到现在,基本上可以针对Android自定义注解做一个短暂收尾,后面还要学习butterknife源码呢,哼!
我们先定义一个MyInvocatio[nHandler实现InvocationHandler的方法
package com.example.mylibrary;
import android.util.Log;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
* 先定义一个Invoke处理类
public class MyInvocationHandler implements InvocationHandler {
private Object target;
private Method method;
public MyInvocationHandler(Object target, Method method){
this.target = target;
this.method = method;
@Override
public Object invoke(Object proxy, Method _method, Object[] args) throws Throwable {
Log.e("test", "method=" + _method.getName());
Log.e("test", "args=" + args[0]);
///< method是解析注解时getDeclaredMethods获得的方法
return method.invoke(target, args);
}
然后解析时我们使用动态代理方式来设置监听事件
Method[] methods = classObj.getDeclaredMethods();
///< 动态代理方式
for (Method method : methods) {
if (method.isAnnotationPresent(OnClicks.class)) {
OnClicks onClicks = method.getAnnotation(OnClicks.class);
///< 控件ID
int[] viewId = onClicks.value();
///< 创建一个点击事件代理对象【点击跳转过去可以发现接口里面有onClick方法】
View.OnClickListener listenner = (View.OnClickListener) Proxy.newProxyInstance(View.OnClickListener.class.getClassLoader(),
new Class[]{View.OnClickListener.class}, new MyInvocationHandler(context, method));
for (int id : viewId) {
///< 4. 获取控件
Method methodFd = null;
try {
methodFd = classObj.getMethod("findViewById", int.class);
View viewObj = (View) methodFd.invoke(context, id);
///< 设置View的setOnClickListener点击事件
Method targetMethod = viewObj.getClass().getMethod("setOnClickListener", View.OnClickListener.class);
///< 会触发MyInvocationHandler的invoke方法
targetMethod.invoke(viewObj, listenner);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
就是这样。个人简单理解其实就是,通过设置控件的setOnClickListener,而setOnClickListener里面是onClick方法,当执行targetMethod.invoke(viewObj, listenner)会触发代理对象的invoke方法,在里面我们就可以执行我们的method方法,进而实现控件的事件注解。
为什么要动态代理,前面也有总结了下。 简单来说:我们再不用修改原有的接口的情况下,可以实现保留原有的调用,同时还能增加额外的处理。否则你可能会涉及到同时修改很多很多的方法...
【继续补上】 其实关于上面动态代理的方式,一开始有点疑惑的,可能知道是这么用。但是和之前的文章的动态代理不太一样:
之前是:我们创建了一个继承某个接口类( 接口类有个方法假设叫onclick() )的实例对象,然后创建InvocationHandler 时作为invoke的target参数传入,同时我们利用Proxy.newProxyInstance生成了该接口的代理实例,然后当执行该实例对象的方法时就会触发InvocationHandler 的invoke方法;此时invoke的参数method自然而然就是接口类的方法 onclick() ,而我们的实例对象作为target传入同时继承了该接口,所以可以直接method.invoke(target, args)即可完成整个动态代理的过程!!!到这里这个还是相对好理解
现在:我们生成了View.OnClickListener的代理实例,这个代理实例作为了控件的 setOnClickListener 方法的参数:
///< 设置View的setOnClickListener点击事件
Method targetMethod = viewObj.getClass().getMethod("setOnClickListener", View.OnClickListener.class);
///< 会触发MyInvocationHandler的invoke方法
targetMethod.invoke(viewObj, listenner);
这个时候点击按钮触发了点击事件?这里可能有疑问?其实我们可以先换个写法来触发InvocationHandler 的invoke方法:
// ///< 设置View的setOnClickListener点击事件
// Method targetMethod = viewObj.getClass().getMethod("setOnClickListener", View.OnClickListener.class);
// ///< 会触发MyInvocationHandler的invoke方法
// targetMethod.invoke(viewObj, listenner);