Android-自定义注解-Java动态代理(Proxy)-动态

作者: MonkeyLei | 来源:发表于2019-07-10 10:25 被阅读0次

我们一路从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);
    }
}

然后解析时我们使用动态代理方式来设置监听事件

ButterKnife.java

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);

     viewObj.setOnClickListener(new View.OnClickListener() {
     @Override
     public void onClick(View v) {
           listenner.onClick(viewObj);
       }
     });

这样来理解相对简单点,也比较清晰。当点击时,调用代理实例的onClick方法,此时就会触发invoke方法。而invoke里面我们需要执行的不是传递过去的method(那个method就是代理实例接口的onClick方法),而是我们注解解析获得的method(这样才能执行注解定义的方法),因此我们需要传递context,同时把需要执行的method(target_method)传递过去,进而完成整个自定义事件注册动态代理实现的整个逻辑。

从以上分析来看:

1.分析的不够透彻,因为还没有去深入了解动态代理原理机制?

2. invoke方法的参数可以是method需要的参数,也可以是动态代理生产的接口实例对象,当事件调用时会触发该接口实例对象方法的调用,进而触发invoke方法。

3. 应该还有很多遗漏,slow down....

目前从实践来看我是这么理解的,也暂且先这么理解, 错了后面认个错啥的,嘿嘿。后续专门去分析下动态代理实现原理机制的时候再说道说道!

相关文章

  • Android-自定义注解-Java动态代理(Proxy)-动态

    我们一路从java注解基础,元注解、自定义注解、反射、代理【动态代理】模式一路到现在,基本上可以针对Android...

  • Java 代理

    静态代理 动态代理 动态代理, 日志切片使用反射获得方法 动态代理, 自定义注解(对注解的方法,使用动态代理添加切...

  • Android-自定义注解-Java动态代理(Proxy)-代理

    上一篇简单说了下动态代理的基础,大概怎么去创建一个动态代理实例。然后有什么好处:往往我们不愿意去修改一些接口方法,...

  • java反射和动态代理

    java动态代理Proxy.newProxyInstance 详解java代理机制(静态代理、动态代理)以及使用场景

  • Java基础:反射

    反射注解动态代理相关阅读 Java基础:类加载器 Java基础:反射 Java基础:注解 Java基础:动态代理 ...

  • java随笔(十一)

    java动态代理源码分析,总结。java动态代理实现步骤: 通过阅读源码发现,动态生成代理对象$Proxy0,该对...

  • 手搓代码-从Java动态代理到AOP

    关键字 java 代理模式 动态代理 自定义注解 泛型使用 AOP springboot 1.java静态代理 遵...

  • JDK动态代理

    JDK动态代理要点: 类:java.lang.reflect.Proxy(动态生成代理类) 接口:java.lan...

  • Java动态代理简析原理

    说下Java动态代理,Spring的AOP就是基于Java的动态代理实现的。动态代理用到的几个类和接口,Proxy...

  • Android-自定义注解-Java动态代理(Proxy)-基础

    Android自定义注解从元注解开始,经过自定义注解,经过反射基本可以自己实现一个仿Butterknife那样使用...

网友评论

    本文标题:Android-自定义注解-Java动态代理(Proxy)-动态

    本文链接:https://www.haomeiwen.com/subject/fmsckctx.html