专栏首页恩蓝脚本android module解耦组件化总体概述(推荐)

android module解耦组件化总体概述(推荐)

原由

移动开发中,随着项目不断的跌代,需求越来越复杂后。项目工程也越来越庞大。那么此时的分module的开发,则是必然的选择了。在最终的组件化之路上,不妨把单一工程比如石器时代,那么接下来简单的拆分工程分多个moudle开来就是铜器时代。

铜器时代之简单分module

演进

由于从复杂的单工程拆分了多个module了,达到了代码及资源的初步的隔离,或需求模块的开发人员,开始专注于自己的需求模块module的开发了。但是随着部分需求有相关性,需要相互调用时。那么问题来了,在AXXX module中

api project(':BXXX')

而在BXXX module中

api project(':AXXX')

这时出现了相互依赖,首先编译器会能不过,会出现Circular dependency,循环相互依赖的问题,这是绝不允许的。

为了解决上述的问题,将AXXX module与BXXX module需要对外提供服务能力支持的,进行封装与抽象。将需要对外暴露接口/协议地方,对其抽象出接口出来。把些这接口独立放在BaseXXXX module中,这样AXXX module与BXXX module,都分别去

api project(':BaseXXXX')

通过BaseXXXX中间module通信去解决AXXX module与BXXX module相互依赖调用通信。

初步的解决方法

为了在BaseXXXX module中,搭建起AXXX module与BXXX module相互通信的桥梁,可以在BaseXXXX module 定义一个通信标识接口:

/**
 *
 * 跨module通讯的 标识 interface接口
 */
public interface IModuleApi {
}

然后主要通过ModuleApiHelper进行通信

public class ModuleApiHelper {

  private static Map<Class<? extends IModuleApi ,IModuleApi  moduleApiMap = new HashMap< ();
  private static Map<Class<? extends IModuleApi ,List<IModuleApi   moduleApiListMap = new HashMap< ();

  /**
   * 跨module 注册进 IKWModuleApi接口,及实现
   * 通常可以在 其它的module中 注册此接口的实现,在用的module中getModuleApi拿到接口实现
   * 这样,用的module 不是 必须依赖compile其它module了
   * @param clazz
   * @param iModuleApi
   */
  public static void register(Class<? extends IModuleApi  clazz, IModuleApi iModuleApi){
    if (null != iModuleApi && null != clazz){
      moduleApiMap.put(clazz, iModuleApi);
    }
  }

  public static void unregister(Class<? extends IModuleApi  clazz){
    if (moduleApiMap.containsKey(clazz)){
      moduleApiMap.remove(clazz);
    }
  }

  public static void register2List(Class<? extends IModuleApi  clazz, IModuleApi iModuleApi){
    if (null != iModuleApi && null != clazz){
      if (moduleApiListMap.containsKey(clazz)){
        List<IModuleApi  iModuleApis = moduleApiListMap.get(clazz);
        iModuleApis.add(iModuleApi);
      }else{
        List<IModuleApi  iModuleApis = new ArrayList< ();
        iModuleApis.add(iModuleApi);
        moduleApiListMap.put(clazz, iModuleApis);
      }
    }
  }

  public static void unregister2List(Class<? extends IModuleApi  clazz){
    if (moduleApiListMap.containsKey(clazz)){
      moduleApiListMap.remove(clazz);
    }
  }

  public static void unregisterAll(Class<? extends IModuleApi  clazz){
    unregister(clazz);
    unregister2List(clazz);
  }

  public static <T extends IModuleApi  List<T  getModuleListApi(Class<T  clazz){
    if (null != clazz){
      if (moduleApiListMap.containsKey(clazz)){
        List<IModuleApi  iModuleApis = moduleApiListMap.get(clazz);
        return (List<T ) iModuleApis;
      }else{
        return null;
      }
    }else{
      return null;
    }
  }

  /**
   * 获取注册绑定过来的IKWModuleApi 实现
   * @param clazz
   * @param <T 
   * @return
   */
  public static <T extends IModuleApi  T getModuleApi(Class<T  clazz){
    if (null != clazz){
      if (moduleApiMap.containsKey(clazz)){
        return (T) moduleApiMap.get(clazz);
      }else{
        return null;
      }
    }else{
      return null;
    }
  }
}

这样比如在AXXX module中将原有AServiceData类是如下的:

public class AServiceData {
  public String getSomeData(){
    return "this is some data";
  }

  public void sayHello(){
    System.out.println("hello");
  }
}

改造成

public interface IAServiceData extends IModuleApi {
  String getSomeData();
  void sayHello();
}

public class AServiceData implements IAServiceData{

  @Override
  public String getSomeData(){
    return "this is some data";
  }

  @Override
  public void sayHello(){
    System.out.println("hello");
  }
}

将IAServiceData接口定义在BaseXXXX module 中。然后AXXX module中进行register相应的服务

public class AModuleService {

  public void init(){
    ModuleApiHelper.register(IAServiceData.class,new AServiceData());
  }
}

这样调用AModuleService的init方法,即可对IAServiceData服务进行注册了。然后即下来,在BXXX module中进行getXXX得到服务即可调用相应的方法了.

在任何需要此服务的方法可如下调用:

IAServiceData iaServiceData = ModuleApiHelper.getModuleApi(IAServiceData.class);

注意

1 register注册时机,需要越早越好,一般建议在各module的有类似的application的onCreate时注册最好。

2 IModuleApi与ModuleApiHelper,和各extends继承IModuleApi接口的接口,需要放在中间通信BaseXXX Module中。各需要通信的module去 compile/api BaseXXX Module即可。

问题

为了保证IModuleApi接口注册有效,需要越早越好进行注册。这样随着项目越来越复杂,需要通信的地方越来越多。统一的ModuleApiHelper,注册的地方将越来越多带的问题也多起来。

1 注册Map容器占用的内存不断的增多。 2 register注册的地方不统一,有些放在各module的类Application的onCreate中,有些可能是放在其它的类中. 3 不支持ui页面的跳转,由AXXX module的AxxActtivy页面跳转到BXXX module的BxxActivity页面中。 4 不支持多进程中应用。

为了解决上述问题,引入了蒸汽时代之ARoute到来。

蒸汽时代之ARoute

由于遍幅的原因,总体概述不详细细述ARoute,下遍再剖析ARoute。总体来说在多module通信中解决了:

1 解决了ui页面的跳转问题。 2 根据需要进行register的问题,且register通过静态注解来的,所以register地方统一比如容易维护。

但是依然不能解决多进程中的应用。

电器时代之Andromeda

Andromeda解决了多进程,跨进程ipc之间的通信过程,同样也支持单进程的通信…

以上就是本文的全部内容,希望对大家的学习有所帮助。。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Android高亮引导控件的实现代码

    最近项目需求是实现高亮功能引导页的效果,查了很多资料Android确实没有类似iOS的抠图的现成控件,就自己写一个,具体如下:

    砸漏
  • Keras实现支持masking的Flatten层代码

    不知道为什么,我总是需要实现某种骚操作,而这种骚操作往往是Keras不支持的。例如,我有一个padding过的矩阵,那么它一定是带masking的,然后我想要把...

    砸漏
  • Android Studio打包jar及aar包的方法

    在 app 宿主工程的 build.gradle dependencies {} 中加入:

    砸漏
  • .NET Core 3.0之深入源码理解Host(二)

    停了近一个月的技术博客,随着正式脱离996的魔窟,接下来也正式恢复了。本文从源码角度进一步讨论.NET Core 3.0 中关于Host扩展的一些技术点,主要讨...

    Edison.Ma
  • Quartz.net官方开发指南 第八课:SchedulerListeners

    SchedulerListeners同TriggerListeners及JobListeners非常相似,SchedulerListeners只接收与特定tri...

    张善友
  • Java应用集群下的定时任务处理方案(mysql)

    一枝花算不算浪漫
  • 体验腾讯云服务器促销2C/4G/5M三年1200元性能综合评测

    时至年中,我们可以看到具有代表性的阿里云、腾讯云商家相继发布年中大促活动,腾讯云从上一个月就开始一直会持续到6月20日,而阿里云目前正式的618活动还没有发布,...

  • Newbe.Claptrap 框架入门,第四步 —— 利用 Minion,商品下单

    接上一篇 Newbe.Claptrap 框架入门,第三步 —— 定义 Claptrap,管理商品库存 ,我们继续要了解一下如何使用 Newbe.Claptrap...

    newbe36524
  • 整数的存储:符号加绝对值表示法

    mwangblog
  • nutz 中 子模块 参数的使用。

    1.支持HttpSession,HttpServletRequest,HttpServletResponse三个参数

    forxtz

扫码关注云+社区

领取腾讯云代金券