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



  • 2017-06-18 02:26:17

    Incorrect string value: '\xF0\x9F\x98\x84\xF0\x9F

    我们可以看到错误提示中的字符0xF0 0x9F 0x98 0x84 ,这对应UTF-8编码格式中的4字节编码(UTF-8编码规范)。正常的汉字一般不会超过3个字节,为什么为出现4个字节呢?实际上是它对应的是智能手机输入法中的表情。那为什么会报错呢?

  • 2017-06-18 02:34:22

    谈mysql中utf8和utf8mb4区别

    MySQL在5.5.3之后增加了这个utf8mb4的编码,mb4就是most bytes 4的意思,专门用来兼容四字节的unicode。好在utf8mb4是utf8的超集,除了将编码改为utf8mb4外不需要做其他转换。当然,为了节省空间,一般情况下使用utf8也就够了。

  • 2017-07-05 09:48:51

    CSS 元素垂直居中的 6种方法

    利用CSS进行元素的水平居中,比较简单,行级元素设置其父元素的text-align center,块级元素设置其本身的left 和 right margins为auto即可。本文收集了六种利用css进行元素的垂直居中的方法,每一种适用于不同的情况,在实际的使用过程中选择某一种方法即可。

  • 2017-07-06 10:02:18

    大白话讲解Promise(一)

    去年6月份, ES2015正式发布(也就是ES6,ES6是它的乳名),其中Promise被列为正式规范。作为ES6中最重要的特性之一,我们有必要掌握并理解透彻。本文将由浅到深,讲解Promise的基本概念与使用方法。

  • 2017-07-11 21:54:14

    MYSQL5.7版本sql_mode=only_full_group_by问题

    一旦开启 only_full_group_by ,感觉,group by 将变成和 distinct 一样,只能获取受到其影响的字段信息,无法和其他未受其影响的字段共存,这样,group by 的功能将变得十分狭窄了

  • 2017-07-14 13:51:58

    NodeJS连接MySQL出现Cannot enqueue Handshake after invoking quit.

    原因在于node连接上mysql后如果因网络原因丢失连接或者用户手工关闭连接后,原有的连接挂掉,需要重新连接;如下代码,每次访问结束都关闭,每次开始访问前重连接下,代码中没有监听连接的fatal错误,copy需谨慎