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



  • 2020-03-17 09:47:05

    video标签视频不自动播放的问题

    添加 muted 属性,就可以通过地址栏进入网页的时候自动播放了,手机端还是有的有限制的,比如iphone浏览器,就不行,苹果手机为了保护用户的流量和用户的意愿,是禁止自动播放的,必须有手动触发。

  • 2020-03-17 14:21:31

    nuxt+pm2 自动化部署及打包后文件自动上传阿里云 oss(精华)

    部署nuxtjs,这一篇文章就够了,pm2 代码自动发布依赖于 git 工具,先将 ssh 密钥配置再你的代码仓库(github 或者 gitLab),具体操作自行 google 或者点击github 配置 ssh。 使用 ssh 密钥链接服务器 s $ ssh-copy-id root@1.2.3.4 # 把本机的 SSH 秘钥添加至服务器,配置成功后,以后就不需要再执行这条 SSH 命令了

  • 2020-03-18 21:15:34

    使用canvas画布解决百度地图自定义图层全球连续显示问题

        基于百度地图的Web API进行自定义图层叠加时,默认的图层只能叠加到全球范围以内,即经度范围为[-180, 180],而无法将图层叠加到默认的全球范围以外,即经度范围超出了[-180, 180]之后,经纬度坐标会自动回归到(0, 0),而导致在地图拖拽时全球以外无法连续显示想要的图层,此时可以基于百度地图的自定义图层将经纬度坐标转为像素点使用画布canvas来解决该问题。解决后效果如下图所示: ———————————————— 版权声明:本文为CSDN博主「宏伟杰作」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/u011284073/article/details/80549950

  • 2020-03-18 21:18:01

    node-canvas实现百度地图个性化底图绘制

    随着nodejs的推出,node的并发和异步的强大能力,越来越多的得到应用,而且取得了非常不错的效果。 作为一个前端工程师对node.js自然有着一份更深的感情,跃跃欲试的心情,总希望能将它应用到产品中来。

  • 2020-03-18 21:19:28

    高德地图和canvas画图结合应用的一些感想(一)

    入了团队才发现,该项目前后端分离,后端工程师已就位主要实现接口,IOS端工程师也已就位,还差一个web前端工程师。背脊一凉,我之前虽然写过一些js和css,虽有点功底但是离前端工程师还是有距离的啊。在和朋友说明情况后,朋友也是胆大,让我试试,主要他实在找不到人了(也有可能目前前端工程师报价都太贵了,创业嘛,能节约就节约,能理解。。。),没办法,走一步算一步吧。