1. Common组件中心化问题
一般的组件化架构的结构是这样的:
随着业务的不断增加,我们都会遇到一个问题,就是common组件越来越大,里面的代码越来越乱,该组件就会变得比较臃肿,难以维护。
问题的出现都是有原因的,我们来分析一下common组件里都放了什么内容:
-
整个项目的一些base的代码
比如BaseActivity,BaseFragment等一些base代码。分析:这种base代码放在common里确实是比较合适的。
-
两个组件间共用的代码
比如数据类和网络接口类。A组件和B组件都用到了某个网络接口返回某个数据。此时对于这个数据类和网络接口类貌似也只能放在common组件里。分析:
两个组件间共用一些代码是很常见的场景,但是把这些代码放在common里合适吗?common是被所有组件模块所依赖的,所以common的含义应该是所有组件公共的代码才能叫common,两个组件间公共的代码不应该放在common里。
而且把两个组件间共用的代码放在common里也会被其他不应该依赖这些代码的组件依赖到,就有可能会被这些组件误使用到。我们知道隔离的最好方式就是编译隔离,所以根本的解决方案就是让其他的组件不能编译依赖到这些代码。
应该如何实现呢?我们下面会说到。
-
基础功能的代码
有些项目呢会把图片加载,网络访问等一些基础功能的代码在common组件里建一个image,network文件夹来进行存放。分析:这样也是不合理的,这些基础功能应该放在基础组件层,新建一个独立的组件来存放。这个问题比较清晰,我们不过多讨论。
所以,经过分析,我们主要需要解决的问题就是两个组件间共用的代码如何存放的问题。
2. “两个组件间共用的代码” 如何存放
一般遇到这种情况的场景是,A组件有某个功能,但是B组件需要用到该功能,此时可以通过A组件提供出来一个“sdk”给到B组件来使用。
“sdk”里包含两部分内容
- 数据类,
- 该功能的接口
暴漏接口类,而不是具体实现类,这样B组件就只依赖了该功能的接口而不是具体实现
"sdk"起到的作用就是“两个组件间的common”,这样就避免了把“两个组件间的common”放在了“所有组件间的common”组件里。
3. 自动生成“sdk”
A组件提供“sdk”给B组件,就如下图所示:
其中ServiceManager的角色ARouter已经帮我们实现了,不想重复造车的可以直接使用ARouter。
我们这里主要讨论的是sdk组件如何来生成,sdk组件也是一个module,如果我们每次都要新建module,手动将接口和数据类摘到新module里岂不是很繁琐。我们可以使用gradle脚本帮我们实现这个功能。
ext {
include_with_api = {
moduleName ->
include(moduleName)
//获得module的根目录
String originDir = project(moduleName).projectDir
//制作的 SDK module的目录
String targetDir = "${originDir}_api"
//制作的 SDK module的名字
String sdkName = "${project(moduleName).name}_api"
System.out