java(Android)跨Module调用对应类方法需求解决方案

2019-06-13 10:09:51

参考地址  java(Android)跨Module调用对应类方法需求解决方案

在开发组件化项目中,遇到一个这样的问题,两个不同的Module相互之间没有任何直接依赖关系,现在需求是需要在Module_A中调用Module_B中的某个类的方法,以下为解决此问题的方法;


采用的核心技术:路由、反射;


解决问题的过程,首先将需要调用的类通过路由注册,注册到路由中心,这里讲Module_B中的类注册到了路由中心,在Module_A中首先先通过路由中心获取到已经注册了的Module_B的类,获取到Class后通过反射原理获取当前对象实例,然后继续通过反射调用调用当前实例对象的对应方法(支持无参方法及有参方法),至此调用方法已实现,具体示例如下:


1、路由注册工具类:


/**

 * Class类路由注册工具类

 * Created by sun.li on 2018/7/6.

 *

 * @author sun.li

 */


public class RouterClassUtil implements RouterInter<Object,Class<? extends Object>>{


    private ConcurrentHashMap<String, Class<? extends Object>> mClassZ = new ConcurrentHashMap();

    private ConcurrentHashMap<String, Object> mClassA = new ConcurrentHashMap();

    private static RouterClassUtil mInstance;


    private RouterClassUtil() {

    }


    public static RouterClassUtil getInstance() {

        if(null == mInstance) {

            synchronized(RouterActivity.class) {

                if(null == mInstance) {

                    mInstance = new RouterClassUtil();

                }

            }

        }

        return mInstance;

    }


    @Override

    public void routerT(String key, Object obj) {

        Object cacheActivity = this.mClassA.get(key);

        if(null == cacheActivity || obj != cacheActivity) {

            this.mClassA.put(key, obj);

        }

    }


    @Override

    public Object invokT(String key) {

        return this.mClassA.get(key);

    }


    @Override

    public void routerV(String key, Class<?> aClass) {

        Class cacheClass = this.mClassZ.get(key);

        if(null == cacheClass || aClass != cacheClass) {

            this.mClassZ.put(key, aClass);

        }

    }


    @Override

    public Class<? extends Object> invokV(String key) {

        return this.mClassZ.get(key);

    }


    /** 获取Object对象*/

    public Object getObject(String key){

        Object object = invokT(key);

        if(null == object){

            try {

                Class<? extends Object> aClass = invokV(RouterHttpClassKey.KEY_MODULE_HTTP_HTTPUTIL);

                if(null != aClass) {

                    object = aClass.newInstance();//通过Class对象实例化当前对象

                }

            } catch (InstantiationException e) {

                e.printStackTrace();

            } catch (IllegalAccessException e) {

                e.printStackTrace();

            }

        }

        return object;

    }

}

2、路由对应Class配置类(此处声明具体的Class类路径,注册时通过反射原理获取对应的Class):


/**

 * 路由跳转Class对应key配置类

 * Created by sun.li on 2018/7/6.

 *

 * @author sun.li

 */


public class RouterHttpClassKey {


    /**

     * HttpUtil

     */

    public static final String KEY_MODULE_HTTP_HTTPUTIL = "**.**.**.util.HttpLibUtil";

}

3、路由注册:


RouterClassUtil.getInstance().routerV(value,correspondingClass);

4、路由调用获取当前的对象并且通过反射调用对应的方法:


4.1、无参方法调用:


/** 调用Module中的对应无参方法*/

public void callMethodInModule(@NonNull String className,@NonNull String methodName){

    Object object = RouterClassUtil.getInstance().getObject(className);

    if (null != object) {

        Method method = getMethod(object,methodName,null);

        if(null!=method){

            try {

                //执行对象object中通过反射获取的方法

                method.invoke(object);

            } catch (IllegalAccessException e) {

                e.printStackTrace();

            } catch (InvocationTargetException e) {

                e.printStackTrace();

            }

        }

    }

}

4.2、有参方法调用(发射调用多参数时因为方法限制,还未想到好的方式):


/**

 * 公共网络请求参数对象

 * Created by sun.li on 2018/7/6.

 *

 * @author sun.li

 */


public class BaseObjectParameterBean {


    public BaseObjectParameterBean(){


    }


    public BaseObjectParameterBean(Class parameterType, Object parameterValue){

        setParameterType(parameterType);

        setParameterValue(parameterValue);

    }


    /** 参数值*/

    private Object parameterValue;


    /** 参数类型*/

    private Class parameterType;


    public Object getParameterValue() {

        return parameterValue;

    }


    public void setParameterValue(Object parameterValue) {

        this.parameterValue = parameterValue;

    }


    public Class getParameterType() {

        return parameterType;

    }


    public void setParameterType(Class parameterType) {

        this.parameterType = parameterType;

    }

}

/** 调用Module中的对应有参方法*/

public void callMethodInModule(@NonNull String className, @NonNull String methodName, List<BaseObjectParameterBean> mList){

    if(null!=mList && mList.size()>0){

        /* 参数类型集合*/

        List<Class> classList = new ArrayList<>();

        /* 参数值集合*/

        List<Object> objectList = new ArrayList<>();

        for (int i = 0; i < mList.size(); i++) {

            BaseObjectParameterBean baseHttpRequestParameterBean = mList.get(i);

            if(null != baseHttpRequestParameterBean){

                if(null != baseHttpRequestParameterBean.getParameterValue() && null != baseHttpRequestParameterBean.getParameterType()){

                    classList.add(baseHttpRequestParameterBean.getParameterType());

                    objectList.add(baseHttpRequestParameterBean.getParameterValue());

                }

            }

        }

        if(classList.size()>0 && objectList.size()>0){

            Object object = RouterClassUtil.getInstance().getObject(className);

            if (null != object) {

                Method method = getMethod(object,methodName,classList);

                if(null!=method){

                    try {

                        //执行对象object中通过反射获取的方法

                        Object[] mObjectList = new Object[objectList.size()];

                        for (int i = 0; i < objectList.size(); i++) {

                            if(null != objectList.get(i)){

                                mObjectList[i] = objectList.get(i);

                            }

                        }

                        method.invoke(object,mObjectList);

                    } catch (IllegalAccessException e) {

                        e.printStackTrace();

                    } catch (InvocationTargetException e) {

                        e.printStackTrace();

                    }

                }

            }

        }

    }else{

        callMethodInModule(className,methodName);

    }

}

private Method getMethod(Object object, @NonNull String methodName, List<Class> mList){

    if(null == object || TextUtils.isEmpty(methodName)){

        return null;

    }

    Method method = null;

    try {


        if(null != mList && mList.size()>0){

            // 父类对象调用子类有参数的方法(反射原理)

            Class[] mClassList = new Class[mList.size()];

            for (int i = 0; i < mList.size(); i++) {

                if(null != mList.get(i)){

                    mClassList[i] = mList.get(i);

                }

            }

            method = object.getClass().getMethod(methodName,mClassList);

        }else{

            method = object.getClass().getMethod(methodName);// 父类对象调用子类方法(反射原理)

        }

    } catch (NoSuchMethodException e) {

        e.printStackTrace();

    }

    return method;

}

4.3、调用示例:


BaseObjectUtil.getInstance().callMethodInModule(RouterHttpClassKey.KEY_MODULE_HTTP_HTTPUTIL,"test");


List<BaseHttpRequestParameterBean> beans = new ArrayList<>();

beans.add(new BaseHttpRequestParameterBean(String.class,"哈哈"));

beans.add(new BaseHttpRequestParameterBean(Integer.class,88));


BaseHttpRequestParameterBean baseHttpRequestParameterBean = new BaseHttpRequestParameterBean();

baseHttpRequestParameterBean.setParameterType(Integer.class);

beans.add(baseHttpRequestParameterBean);


BaseObjectUtil.getInstance().callMethodInModule(RouterHttpClassKey.KEY_MODULE_HTTP_HTTPUTIL,"test2",beans);

调用结果:

07-06 16:07:29.862 10329-10329/cc.**.** E/HttpLibUtil:: 我是HttpLib中的test方法

07-06 16:07:29.862 10329-10329/cc.**.** E/HttpLibUtil:: 我是HttpLib中的test2方法,str=哈哈 i=88



  • 2021-04-15 10:32:18

    怎么给 headless chrome添加cookies

    In puppeter you have access to the session cookies through page.cookies(). So once you log in, you could get every cookie and save it in a json file:

  • 2021-04-15 10:51:21

    如何通过Devtools协议拦截和修改Chrome响应数据

    在日常研究中,我们经常碰到大量JavaScript代码,我们首先要深入分析才能了解这些代码的功能及具体逻辑。这些代码代码可能会被恶意注入到页面中,可能是客户送过来需要我们帮忙分析的脚本,也可能是我们的安全团队在网页上找到的引用了我们服务的某些资源。这些脚本通常代码量不大、经过混淆处理,并且我们总是需要经过多层修改才能继续深入分析。

  • 2021-04-19 10:54:39

    block和delegate的区别

    代理 可读性高 大部分可以属性 block 写的代码少 一般作为参数 通知 占用资源

  • 2021-04-19 11:00:23

    浅谈block和delegate的使用

    委托是协议的一种,顾名思义,就是委托他人帮自己去做事。委托是给一个对象提供机会对另一个对象中的变化做出反应或者影响另一个对象的行为。其基本思想是:两个对象协同解决问题,并且打算在广泛的情形中重用。委托指向另一个对象(即它的委托)的引用,并在关键时刻给委托发消息。消息可能只是通知委托发生了某件事情,给委托提供机会执行额外的处理,或者消息可能要求委托提供一些关键的信息以控制所发生的事情。委托的作用主要有两个,一个是传值,一个是传事件。

  • 2021-04-19 11:36:44

    iOS 组件实现方案

    什么才是好架构,为什么要组件,组件设计的优点

  • 2021-04-25 09:53:18

    android debug速度特别慢有时候卡住

    一直提示定在 Starting LLDB server。可能的原因是 Android Studio编译速度太慢了,就会一直卡在Starting LLDB server。可以通过设置 Run/Debug Configurations ——> Debugger ——> Debug type 为 Java 跳过 C/C++的调试,起码实现对 Java 程序的调试

  • 2021-04-25 09:54:19

    sequelize 时区配置

    sequelize 默认情况下, 保存日期时会转换成 +00:00时区,