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



  • 2018-12-18 15:33:01

    <![CDATA[]]>和转义字符

      此标记用于xml文档中,我们先来看看使用转义符的情况。我们知道,在xml中,”<”、”>”、”&”等字符是不能直接存入的,否则xml语法检查时会报错,如果想在xml中使用这些符号,必须将其转义为实体,如”&lt;”、”&gt;”、”&amp;”,这样才能保存进xml文档。

  • 2018-12-26 15:06:00

    PHP-FPM运行状态的实时查看及监控详解

    php-fpm和nginx一样内建了一个状态页,对于想了解php-fpm的状态以及监控php-fpm非常有帮助。这篇文章就给大家详细介绍了PHP-FPM运行状态的实时查看及监控,有需要的朋友们可以参考学习,感兴趣的朋友们下面来一起看看吧。

  • 2018-12-26 16:12:56

    nginx+php-fpm模式php内存泄漏探究

    这里要重点说一下第三步骤。第三步涉及到php-fpm进程生命周期的东西。一个php-fpm的生命周期大致是这样的:模块初始化(MINIT)-> 模块激活(RINIT)-> 请求处理 -> 模块停用(RSHUTDOWN) -> 模块激活(RINIT)-> 请求处理 -> 模块停用(RSHUTDOWN)……. 模块激活(RINIT)-> 请求处理 -> 模块停用(RSHUTDOWN)-> 模块关闭(MSHUTDOWN)。在一个php-fpm进程的生命周期里,会有多次的模块激活(RINIT)-> 请求处理 -> 模块停用(RSHUTDOWN)的过程。这个“请求处理”的大致过程是这样的:php读取相应的php文件,对其进行词法分析,生成opcode,zend虚拟机执行opcode。

  • 2019-01-01 21:38:51

    php使用curl设置超时的重要性

    网站登录不了,原因是没有可用的 PHP 子进程来响应新的请求了。这可能是是由于PHP-curl 没有设置超时时间引起的。

  • 2019-01-01 21:42:34

    php-fpm 启动参数及重要配置详解

    如果file_get_contents请求的远程资源如果反应过慢,file_get_contents就会一直卡在那里不会超时。我们知道php.ini 里面max_execution_time 可以设置 PHP 脚本的最大执行时间,但是,在 php-cgi(php-fpm) 中,该参数不会起效。真正能够控制 PHP 脚本最大执行时间的是 php-fpm.conf 配置文件中的request_terminate_timeout参数。