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 Studio 多层级 Module 对 aar 引用问题解决方法

    最近碰到这么个恶心的问题 问题:有个arr文件被放到Module A中引用,现在Module B又依赖了Module A,则在编译过程中会发生错误,Module B找不到aar文件.(同时如果又有Module C 依赖了Module B,C也会出同样的问题) 解法: 1.正常给一个module加入aar文件的步骤是: 1.把aar文件放入module文件夹下libs包下 2.然后在项目的build.gradle文件的android节点下加入 3. 1. repositories { flatDi

  • Android Studio中导入module的方法(简单版)

    1.把要导入成Mudle的项目修改成符合Library的格式 修改该项目中bulid.gradle文件中第一行代码 把 apply plugin: 'com.android.application' 修改为 apply plugin: 'com.android.library' 然后,修改AndroidManifiest.xml文件中配置信息,此处主要是把原来配置的项目Style等配置以及MainActivity配置删除,这样处理是为了防止重复.以下以一个我的Moudle文件的AndroidMa

  • Android Data Binding 在 library module 中遇到错误及解决办法

    记一次 Data Binding 在 library module 中遇到的大坑 使用 Data Binding 也有半年多了,从最初的 setVariable,替换 findViewById,到比较高级的双向绑定,自定义 Adapter.Component,查看源码了解编译.运行流程,也算是小有成果,且没有碰到 Data Binding 本身实现上的问题. 然而,最近在一次重构组件化(见 MDCC 上冯森林的<回归初心,从容器化到组件化>)的过程中,碰到了一个比较严重的 BUG.已经提交 i

  • Android studio 如何删除项目 module

    在Android Studio中想要删除某个module时,在Android Studio中选中module,右键发现没有delete,如图: Android Studio对module做了一个保护机制,module是不能随意删除的,要删除必须先从module列表中移除. 移除方式有两种: 1.File菜单下Project structure...,选中你要移除的module,然后按红色的'-'按钮,这个时候仅仅是在Android Studio目录结构中删除,并没有从硬盘删除,如果这个modul

  • Android Studio 合并module到统一文件夹的方法

    在同一项目中,引用了多个module,长短不一的命名显得比较乱, 这里想把引入的module放到统一的目录,方便管理 在项目中新建一个文件夹 1.先正常导入module到项目中 2.把导入的module拖入到新建好的文件夹中 3.打开setting.gradle 在里面映射路径 完成! 下面看下android studio关于同名资源文件的合并 最近在开发过程中遇到了一个问题,在调整一个背景drawable文件的时候发现修改内容没有生效. 各种查找问题之后发现是由于另外一个模块内存在同名资源文件

  • 如何修改Android Studio创建module时默认的compileSdkVersion

    前言 今天下午的时候有人问到,AS 哪里能配置 build.gradle 的模板,从而达到每次新建 module 时默认的 compileSdkVersion 用指定的值而不是取最新 SDK 的 api-string. 解决方案 先看了 Preferences,并没相关的 template 能修改 build.gradle,再 Google 了一会,只有该帖子提及到 build.gradle 的模板文件的位置. 按照给出的路径 <android-studio>/plugins/android/

  • Android主项目与Module中R类的区别详解

    前言 大家都知道 Android 项目中会通过自动生成一个 R.java 类的方式来保存项目中所有资源文件的标识.在主项目中生成的 R.java 中的资源声明是一个静态常量,而在 module 中它却是一个静态变量.这是为什么呢?我们知道在 java 中如果某个值被声明成常量(用 final 修饰),则在编译后,该常量会被直接替换成值.而在 java 语法中,注解的属性和 switch-case 中的 case 表达式,必须使用常量或者直接使用值,否则会报语法错误. 下面我们会展开讨论下为什么

  • Android Studio彻底删除项目 Android Studio彻底删除Module

    Android Studio这样才能彻底删除项目,具体操作如下 1.Android Studio彻底删除Module 当不需要某个Module(工程)时,删除 在"Project"视图中选择需要删除的module名,此处删除"app",点击右键,选择"Open Module Setting",出现如下界面,然后选择左上角的"-"号,将此module从"Test"项目列表中移除(并没有真正的从硬盘删除) 再次

  • Android Studio导入Project与Module的方法及实例

    Gradle Project项目.Module模块导入 最近看到网上很多人在抱怨,Android Studio很难导入github上下载下来的一些项目,主要包括: 1.导入就在下载Gradle 2.根本导不进 下面我分2部分来讲解正确的导入姿势: 1.导入完整的Github Project 我们在github上找一个项目 工程目录如上,里面的东西其实分为2部分,工程相关和项目相关 工程相关用于配置整个项目的编译环境和依赖,项目相关就是你的代码和配置文件啦 我们先来看工程相关,他包含这样几个文件夹

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

    原由 移动开发中,随着项目不断的跌代,需求越来越复杂后.项目工程也越来越庞大.那么此时的分module的开发,则是必然的选择了.在最终的组件化之路上,不妨把单一工程比如石器时代,那么接下来简单的拆分工程分多个moudle开来就是铜器时代. 铜器时代之简单分module 演进 由于从复杂的单工程拆分了多个module了,达到了代码及资源的初步的隔离,或需求模块的开发人员,开始专注于自己的需求模块module的开发了.但是随着部分需求有相关性,需要相互调用时.那么问题来了,在AXXX module中

  • Android组件化原理详细介绍

    目录 什么是组件化? 为什么使用组件化? 一步步搭建组件化 1.新建模块 2.统一Gradle版本号 3.创建基础库 4.组件模式和集成模式转换 5.AndroidManifest的切换 6.*业务Application切换 组件之间的跳转 1.添加依赖 2.初始化ARouter 3.添加跳转 组件之间的数据传递 1.定义接口 2.实现接口 组件Application的动态切换 1.定义抽象类 BaseApplication 继承 Application 2.所有的组件的 Application

  • Android开发组件化架构设计原理到实战

    目录 为什么需要组件化 组件化和模块化 模块化架构 组件化架构 组件化带来的优势 组件化需解决的问题 资源冲突解决 AndroidManifest 独立调试 单工程方案 多工程方案 页面跳转 Arouter 实现组件间方法调用 组件化的消息通信方式选择 广播 事件总线 Application生命周期分发 为什么需要组件化 小项目是不需要组件化的.当一个项目有数十个人开发,编译项目要花费10分钟,修改一个bug就可能会影响到其他业务,小小的改动就需要进行回归测试,如果是这种项目,那么我们需要进行组

  • Android组件化、插件化详细讲解

    目录 什么是组件化(通俗易懂) 反射的写法 反射的⽬的 关于DEX: 插件化原理:动态加载 问题⼀:未注册的组件(例如Activity)不能打开 问题⼆:资源⽂件⽆法加载 插件化有什么用? 什么是组件化(通俗易懂) 通俗易懂来讲就是,拆成多个module开发就是组件化. App的部分功能模块在打包时并不以传统⽅式打包进apk⽂件中,⽽是以另⼀种形式⼆次封装进apk内部,或者放在⽹络上适时下载,在需要的时候动态对这些功能模块进⾏加载,称之为插件化.这些单独⼆次封装的功能模块apk,就称作插件,初始

  • 浅谈android组件化之ARouter简单使用

    ARouter是阿里巴巴开源出来的一款android路由框架,github地址为 : https://github.com/alibaba/ARouter 至于ARouter的诸多好处我就不介绍了,这里主要讲解在项目组件化下,ARouter的一些简单使用 先贴上工程目录: 工程一共分为4个模块,基础组件app.基础服务(包涵路由服务)basecommonlibrary模块.业务模块libraryone.业务模块librarytwo; 在4个模块的gradle文件当中加入如下代码: android

  • Android组件化开发路由的设计实践

    调研了一下目前的路由框架,ARouter(阿里的),ActivityRouter都使用了apt技术 编译时注解,个人想法是一口吃不成胖子,先做个比较实用的. VpRouter路由框架主要应用于组件化开发中 设计目的 解耦 跨模块跳转 方便服务器配置schema,实现动态配置跳转目标 对外部提供远程访问的功能,实现跨应用调用响应 主要功能点 支持intent,http,schema三种跳转 路由表支持xml配置,可自定义,支持多路径 有拦截器 同时支持反射和隐式意图 支持结果回调 支持参数传递 链

  • 详解Android业务组件化之URL Schema使用

    前言: 最近公司业务发展迅速,单一的项目工程不再适合公司发展需要,所以开始推进公司APP业务组件化,很荣幸自己能够牵头做这件事,经过研究实现组件化的通信方案通过URL Schema,所以想着现在还是在预研阶段,很有必要先了解一下URL Schema,看看是如何使用的?其实在之前做Hybrid混合编程的时候就接触过URL Schema,总来的来说还不算陌生,今天就来回顾总结一下. 什么是 URL Schema?  android中的scheme是一种页面内跳转协议,是一种非常好的实现机制,通过定义

  • Angular组件化管理实现方法分析

    本文实例分析了Angular组件化管理实现方法.分享给大家供大家参考,具体如下: 在做sass产品页面的时候,往往每个页面的header和footer都是一样的,还有最近我做的页面,类似datetimepicker这种组件,其实都是可以复用的代码,所以如果能把这些公用的UI组件提取出来,对于维护就会方便很多啦!! angular框架就支持这种组件化管理,不过也有优缺点,我先来说实现方法哈! index.html:没有用到路由,所以js都是src生引进来的 <head> <title>

  • 深入理解Vue.js轻量高效的前端组件化方案

    Vue.js通过简洁的API提供高效的数据绑定和灵活的组件系统.在前端纷繁复杂的生态中,Vue.js有幸受到一定程度的关注,目前在GitHub上已经有5000+的star.本文将从各方面对Vue.js做一个深入的介绍. Vue.js 是我在2014年2月开源的一个前端开发库,通过简洁的 API 提供高效的数据绑定和灵活的组件系统.在前端纷繁复杂的生态中,Vue.js有幸受到一定程度的关注,目前在 GitHub上已经有5000+的star.本文将从各方面对Vue.js做一个深入的介绍. 开发初衷

  • 使用JSX实现Carousel轮播组件的方法(前端组件化)

    在我们用 JSX 建立组件系统之前,我们先来用一个例子学习一下组件的实现原理和逻辑.这里我们就用一个轮播图的组件作为例子进行学习.轮播图的英文叫做 Carousel,它有一个旋转木马的意思. 上一篇文章<使用 JSX 建立 Markup 组件风格>中我们实现的代码,其实还不能称为一个组件系统,顶多是可以充当 DOM 的一个简单封装,让我们有能力定制 DOM. 要做这个轮播图的组件,我们应该先从一个最简单的 DOM 操作入手.使用 DOM 操作把整个轮播图的功能先实现出来,然后在一步一步去考虑怎

随机推荐