☰
Android组件化实战:从架构分层到Gradle配置指南
2026/9/28 14:27:16 网站建设 项目流程

做 Android 开发久了,一定会撞上“组件化(Modularization)”这个词。项目从几万行代码膨胀到几十万行时,改一个公共方法,编译要等两分钟;合代码永远在冲突;发布一个版本要协调三个团队。这个时候再去讨论组件化,已经不是技术时髦,而是被实际问题逼出来的选择。这篇文章照着我的实际操作路径来写,先讲清楚组件化的核心概念和分层思路,再给出一套能落地的模块拆分与 Gradle 配置流程,然后把 FileProvider 冲突、资源重复、循环依赖这些容易翻车的细节一个个拆开,最后会聊一些关于推行节奏的个人体会。适合正在准备重构、或者已经开始拆模块但总觉得别扭的 Android 开发者。

1. 组件化到底是什么,先想清楚它解决什么问题

1.1 单体工程的四个典型痛点

在很多中小型项目里,先活下来再谈架构是常态。第一版 App 可能就一个 app module,里面按包名分 activity、fragment、adapter、model,跑得也算顺畅。问题是这种单体结构撑不过某个规模点。我从实际项目里观察,最先爆掉的一般是四个问题。

第一个是耦合。一个负责“下单”的按钮,点击之后既要调登录、又要调支付、还要调埋点,几年下来业务逻辑散落在各处。想改一个下单状态,你根本说不清会影响多少个页面。第二个是编译时间。模块越多,其实拆分后的增量编译会降下来,但单体工程是改动任何一层,整个工程都要重新编译。尤其是 Kotlin 工程,两分钟起步算是常态,盯着进度条发呆的时间足够写完一个接口。第三个是协作冲突。我和另一个同事同时改同一个 Activity,git 冲突只是表面体感,真正难受的是“你把我昨天改的方法覆盖了”。第四个是回归成本。没有边界就没有测试范围,发版之前所有人都要跟着做回归,因为没人敢保证某个隐藏依赖会不会坏。

这些痛点不是架构好不好看的问题,是会实实在在拖慢迭代速度的问题。组件化就是在这种背景下出现的:把一个大单体按业务边界拆成多个可独立编译的模块,模块之间通过明确接口通信,从而让耦合可控、编译更快、协作边界更清晰。

1.2 模块化、组件化、插件化的边界

刚接触组件化的人,很容易把“模块化”和“组件化”混在一起。我自己的理解是:模块化更偏代码层面,比如抽一个 network 模块、一个 utils 模块,大家都依赖它,目的是复用;而组件化更偏业务层面,比如登录组件、订单组件、首页组件,每个组件都是一个相对完整的业务闭环,可以单独开发、单独编译,甚至单独调试。组件化是模块化思路在业务维度的延伸。

插件化则是另一条路,它强调运行时加载,把代码逻辑放在 dex 或插件包里,动态下发和更新。插件化对热更新和包体积有帮助,但技术复杂度和限制也更高,很多方案已经慢慢退出主流视线。组件化没有插件化那么重,它是在编译期和工程结构上做隔离,所有模块最终还是会打进同一个 APK,只是开发期可以独立构建。这三个概念边界理清楚之后,再去做技术选型就不会被名词绕晕。我的建议是,除非有强动态化需求,否则优先考虑组件化,性价比最高。

维度模块化组件化插件化
拆分对象代码层、功能库业务闭环可执行代码单元
运行方式编译期合并编译期隔离,运行期同进程协作动态加载、独立更新
独立调试不一定支持组件化的基本能力支持但复杂度高
维护成本低中高
稳定性风险低中依赖兼容性

1.3 不是所有项目都需要组件化

说了一句“组件化很好”,不代表它适合所有项目。我见过一个只有三个人维护的 App,业务也不复杂,硬是参考大厂拆了十多个模块,结果平时根本不敢动模块边界,做需求要先想这个代码该放哪里,效率反而下降。组件化是有成本的,模块划分、路由、初始化、构建脚本都要有人维护。

我一般会拿四个指标来判断:并行开发人数是否超过 5 人、核心业务模块之间是否已经出现频繁的“互相调用”、一次全量编译是否已经超过 1 分钟、发版前是否需要跨模块做大量回归。只要满足两三条,就可以认真考虑组件化。如果都不满足,那不如先把手里的单体工程整理干净,保持清晰的包结构和分层,等痛点真的来了再动手。架构不是越复杂越好,合适才是最好。

2. 组件化架构的分层设计与通信原理解析

2.1 四层架构:壳 App、业务组件、功能组件、基础库

组件化的落地形态,我通常画成四层。最上面是壳 App,它本身不写具体业务,只负责两件事:声明 Application,并在启动阶段把各个组件需要的初始化代码都执行掉;再就是把组件之间的路由表、服务注册表装配起来。壳 App 是唯一一个会直接依赖所有业务组件的模块,可以把它理解成组装车间,只管把零件装成一台能跑的机器。

第二层是业务组件,比如登录、订单、消息、首页。每个业务组件都应该能独立编译,内部是完整的业务闭环。业务组件之间不允许直接互相依赖,A 组件想跳转到 B 组件页面,必须走路由;想调用 B 组件的能力,则要面向接口。第三层是功能组件,比如分享、支付、埋点、推送。功能组件和具体业务无关,但被一个或多个业务组件依赖,所以它的接口要尽量稳定,否则一改就会波及相关业务。最下面是基础库,包括网络、图片加载、数据库、加密、工具集合等,属于整个工程的“地基”,应该尽量不依赖上层任何业务。

依赖方向必须是从上到下单向流动。壳依赖业务组件,业务组件依赖功能组件,功能组件和业务组件都依赖基础库。只要出现反向依赖,比如基础库想调用业务组件的某个方法,架构就变味了,后续每次改动都容易变成打地鼠。判断层是否合理最简单的方法,是问一句:这个模块如果被删掉,其它模块还能不能编译通过?如果答案是不确定,那多半是边界画得不清楚。

2.2 页面跳转用路由,逻辑调用靠接口下沉

组件化之后,最直接的变化是:Activity 之间不能直接Intent跳转了。因为在编译期,壳以外的组件彼此不可见,组件 A 的 class 对组件 B 来说就是不存在。要让 A 跳到 B 的页面,常规做法是引入路由。路由本质是一个维护“路径到组件入口”的注册表,A 只需要传一个类似/order/detail?id=100的字符串,路由框架根据注册表找到对应的 Activity 并完成跳转。这样 A 不依赖 B 的字节码,只依赖一个约定的字符串协议。

逻辑调用比页面跳转稍微绕一层。比如登录组件要向订单组件提供“当前用户是否登录”的能力。最稳妥的做法是在基础库定义接口,比如ILoginService,基础库本身不实现,真正的实现放在登录组件内。启动阶段,壳 App 或者路由框架拿到实现类并注册到服务表;订单组件在使用时,通过服务表拿ILoginService的实例来调用。这就是常见的接口下沉加依赖注入,本质是让高层模块依赖抽象而不是依赖具体类。事件总线也可以做跨组件通知,比如登录成功后发一个全局事件,订单页收到后刷新状态,但事件总线不宜承载高频、强类型的数据传输,否则出了问题很难排查。我的经验是:页面跳转优先路由,数据传递优先接口,事件通知只做弱耦合的广播式场景。

2.3 Debug 模式与独立编译开关的设计

组件化要真正提升开发效率,业务组件必须可以单独跑起来。这意味着每个业务组件在开发期需要被当作 application 模块,而在发布期被当作 library 模块。这个切换在 Gradle 里是通过一个布尔开关控制的。通常在gradle.properties里定义isBuildModule,模块的build.gradle根据它决定应用com.android.application还是com.android.library插件。同时,业务组件还要提供一套独立的AndroidManifest.xml,里面声明一个调试专用的 Application 和一个入口 Activity,用来启动组件内部的页面列表。

我之前遇到过一种比较常见的误区:独立调试时,在组件里 new 了一堆假的测试数据,结果发布时忘了移除,把这些调试入口留到了线上包。比较好的做法是,把调试用的 Application 和入口 Activity 放在src/debug/这个 source set 下,主src/main/只保留标准的 library 配置。这样发布构建时,debugsource set 根本不会参与编译,天然隔离,不需要你手动删除。配合 Gradle 的sourceSets配置,就能做到一套代码同时满足独立运行和集成运行两种场景。这里面的细节我放到下一节展开。

3. 实操:把一个普通 Android 工程改造成组件化工程

3.1 拆分前先画依赖图和边界清单

动手改 Gradle 前,先做静态分析。我一般先把当前工程的包结构和模块间依赖梳理清楚。最简单的方式是看 import 关系:如果 order 包下的代码大量 import product 包下的类,说明这两个业务边界耦合严重;如果底层 util 包被所有业务包依赖,那它就是天然的基础库候选。建议用 Android Studio 的 Dependencies 窗口跑一下./gradlew :app:dependencies,把依赖树保存下来,这样拆完之后可以对比。

接下来给模块画边界,这一步不要只看代码,更要看产品语义。比如登录、注册、个人中心可以归到“用户组件”,订单列表、订单详情、售后可以归到“订单组件”,支付虽然是通用能力,但它有大量业务规则,通常作为一个功能组件而不是业务组件。画好边界清单后,先不急着拆,先在文档里把每个模块的“负责范围”和“对外接口”写出来。没有这一步,后面边拆边吵架,非常消耗团队耐心。边界清单里还要标记出风险点:哪些类你发现既被 A 依赖又被 B 依赖,这类代码要么下沉到基础库,要么抽成新组件,提前想好。

3.2 Gradle 配置里的关键开关与注意事项

新版本的 Android Studio 默认用 Gradle Kotlin DSL,但核心逻辑和 Groovy 大同小异。我们需要在根目录的gradle.properties中加一个开关:

isBuildModule=false

如果只想让个别模块参与独立调试,也可以把开关细化成isBuildLoginModule、isBuildOrderModule。然后在业务组件如login/build.gradle中读取:

if (isBuildModule.toBoolean()) { apply plugin: 'com.android.application' } else { apply plugin: 'com.android.library' }

这里有一个非常容易踩的坑:一个 module 从 library 切到 application 后,原来 library 使用的namespace、resourcePrefix这些配置不会有问题,但 AndroidManifest 中的<application>节点不能出现在 library 的主 manifest 里。所以我建议主 manifest 只保留 library 版本,另建一个src/debug/AndroidManifest.xml放调试用的 application 节点和入口 Activity。

依赖关系同样要提前处理。组件作为 library 时,依赖使用api还是implementation要格外小心。api会把依赖传递到上层,implementation不会。组件化工程里,我倾向于对基础库使用api,对内部细节使用implementation。比如网络框架是基础库的能力,业务组件需要直接使用 OkHttp 的类,这时基础库对外暴露 OkHttp 相关方法,可以在基础库中通过api暴露;但一个业务组件内部用的图片加载库,不应该让其他组件感知,就该用implementation隔离掉。原则是:把需要公开的接口通过api暴露,把实现细节用implementation藏起来。

3.3 组件独立调试时的 Application 与 Manifest 处理

独立调试时,业务组件需要一个能真正运行的 Application。可以写一个DebugApplication,放在src/debug/java/下,继承 Application,在里面初始化自己模块需要的数据和 mock 环境。因为独立调试时,壳 App 不存在,组件必须自己承担 Application 的职责。等切回集成模式,这个DebugApplication不会被编译进 APK,完全没有侵入线上包。

Manifest 同理,src/debug/AndroidManifest.xml可以这样组织:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"> <application android:name=".DebugApplication" android:theme="@style/Theme.AppCompat.Light" android:label="登录组件调试"> <activity android:name=".DebugHomeActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>

主 manifest 只放组件自己的页面、服务、权限等,根节点不需要写<application>。为了安全,建议在build.gradle里给 debug 模块的 Application 加一个特殊后缀,比如applicationIdSuffix ".debug",避免覆盖正常环境。

这里还有一个团队协作问题:不是每个组件都需要配一套调试 Application。如果组件很小,比如分享组件,它根本不依赖页面,没必要独立跑成 App;只有业务组件(登录、订单、首页)才有独立调试价值。别把每个功能组件都加调试入口,否则 Gradle 配置会越来越乱。

3.4 跨组件数据传递与接口调用落地

跨组件页面跳转,最简单的是直接接一个成熟路由框架,比如 ARouter,也可以通过 Gradle 插件在编译期生成路由表。ARouter 的用法大家应该都见过:在目标页面上加注解,调用时用ARouter.getInstance().build("/order/detail").withLong("id", 100L).navigation()。路由路径的命名要全局唯一,建议按组件名做前缀,比如/order/detail、/login/main,避免两个组件定义相同路径导致跳错。

如果你不想引入大而全的路由框架,也可以自建一个轻量路由:用ConcurrentHashMap保存路径到Class的映射,在组件初始化时注册,跳转时通过Class.forName或显式映射找到目标 Activity。这种方式虽然少了参数校验和拦截器,但胜在简单可控,适合中小项目。

对于逻辑调用,我强烈建议在基础库建一个服务注册表:

object ServiceRegistry { private val services = ConcurrentHashMap<String, Any>() fun register(serviceName: String, impl: Any) { services[serviceName] = impl } @Suppress("UNCHECKED_CAST") fun <T> get(serviceName: String): T? = services[serviceName] as? T }

基础库定义好接口和 key,比如登录服务:

interface ILoginService { fun isLogin(): Boolean fun getUserInfo(): UserInfo? } const val LOGIN_SERVICE = "ILoginService"

登录组件在初始化时把自己注册进去,订单组件通过ServiceRegistry.get<ILoginService>(LOGIN_SERVICE)调用,两个模块在编译期完全解耦。这套模式也可以配合依赖注入框架使用,但自研服务注册表的维护成本最低,很容易让团队理解。

4. 组件化改造中容易被忽略的坑与排查实录

4.1 FileProvider 与 manifest 合并冲突

组件化工程里,多个模块可能都需要访问文件。比如头像上传需要拍照,订单组件要加载本地文件,分享组件要给第三方 App 传图。这些场景绕不开FileProvider,因为 Android 7.0 之后对file://Uri 做了限制,必须用 content Uri。

问题就出在 FileProvider 的authorities上。如果每个模块都照抄安卓官方示例的配置,把 authorities 写成"${applicationId}.fileprovider",多个组件在 manifest 合并时就会出现同一个 content provider 重复注册。合并工具可能不报错,但 APK 安装时系统会检查 provider authority,一旦发现重复,会直接安装失败,报类似INSTALL_FAILED_CONFLICTING_PROVIDER;如果侥幸装上了,运行时也可能因为 provider 查找返回多个或空值而崩溃。我排过的一个线上问题,就是第三方统计 SDK 注入的 provider 和业务组件的 provider 撞了 authority,导致用户安装新包必崩。

解决办法有两层。第一,每个模块声明 FileProvider 时,authorities 要带模块专属后缀,例如"${applicationId}.fileprovider.login"。第二,如果确实需要统一出口,可以在壳 App 里只保留一个 FileProvider,把其他模块的 fileprovider 配置全部去掉,并在壳模块集中配置映射路径。推荐后者,因为 provider 数量本身也多不到哪去,集中管理更容易排查。合并完成后,建议在build/outputs里检查最终 merged manifest,确认 provider 列表里没有重复的 authority,这个习惯能省很多事情。

4.2 资源冲突:R 文件、资源命名哨兵

资源命名是组件化最容易“平时没事、一上线就出事”的环节。在单体工程里,资源文件名即使重了,Gradle 也能用主工程覆盖模块资源;但组件化后,两个业务组件同时定义了activity_main.xml,合并时按模块顺序取值,谁排在后面不一定,结果就是 A 组件跑出来的布局是 B 组件的,界面完全错乱。你说它是编译错误吧,编译不报错;你说它不是问题吧,用户看到的页面是歪的。

规范做法是约定资源前缀。比如订单组件所有资源以order_开头,登录组件以login_开头。Android Gradle Plugin 里可以给库模块设置resourcePrefix "order_",设置后如果该模块出现order_前缀以外的资源名,构建时会报 Warning 或者 Lint 提示,起到强制提醒作用。但这个检查不是编译阻断,无法 100% 拦截,所以关键在于团队编码规范的执行力。

还有一个比较隐蔽的坑:R文件的引用路径。组件化后,R类在每个模块是独立生成的,代码里引用自己模块的R没问题,但如果想把另一个组件的资源引用过来,就必须依赖那个组件的 R 类,这会让两个组件产生编译期依赖,违背组件化初衷。所以跨组件的资源要尽量下沉到基础库,比如通用颜色、字体、间距,放到common_ui组件里,统一由它导出。具体业务对这一块的诉求是动态主题,那就通过基础库提供的主题接口传值,不要直接引用别的组件资源。

4.3 循环依赖与“组件间互相 new”的坏味道

多模块工程最常见的 Gradle 报错就是循环依赖:Could not resolve project :login. Required by project :order或者Circular dependency between the following tasks。这种问题出现的原因往往不是构建脚本配置错了,而是模块边界本身画歪了。比如登录组件想获取订单页的信息,订单组件又想检查登录状态,两边互相引对方的接口,代码层面看起来没什么,构建系统可不管这些,直接给你一个环。

我的处理思路是:把互相需要的模型和接口下沉到基础库,或者重新定义谁依赖谁。比如把用户信息和登录状态放到基础库的ILoginService,订单组件只需要依赖接口,不需要依赖登录组件的具体实现;订单页要跳转登录页,通过路由解决。这样依赖关系就从“login <-> order”变成了“login 和 order 都朝着基础库和路由”。另外,团队里如果有人为了省事直接new另一个组件的类,一般在 code review 时我会建议改成服务注册或路由,因为这种硬编码依赖在你加了边界规则后会立刻变成编译错误,早发现比晚排查好。

排查循环依赖时,可以用 Android Studio 自带的 Gradle 依赖分析,也可以在根目录执行./gradlew :app:dependencies输出依赖树,重点看标红的循环节点。如果你的工程是用 AGP 7 以上版本,构建器通常会提示哪个 task 参与环,顺着提示找模块声明即可。

4.4 Application 初始化顺序混乱怎么办

组件化之后,原来由一个 Application 集中onCreate的初始化代码,被拆到了各个业务组件里。立即会面临一个很现实的问题:每个组件都要求在主进程启动时尽快初始化,但它们的初始化顺序有依赖。比如统计 SDK 必须先启动,之后才能初始化依赖它的埋点组件;推送组件必须在用户登录后带上 userId,否则服务端下发消息对不上号。

一个简单的做法是壳 App 里定义一个组件初始化列表:

class App : Application() { override fun onCreate() { super.onCreate() LoginInitializer.init(this) OrderInitializer.init(this) PayInitializer.init(this) } }

这种方式胜在直观,但问题也很明显:列表变长后,顺序靠人工维护就特别容易出错。更稳妥的方案是定义统一的初始化接口,例如IModuleInit,每个组件提供实现,壳通过反射扫描注解或者显式注册来按序执行。

更高阶一点的方案是用androidx.startup。这个库通过 ContentProvider 自动初始化应用启动时需要的组件,并且支持声明依赖顺序。简单说,框架会自己分析初始化器之间的依赖,按拓扑序执行。但注意,ContentProvider 初始化发生在 Application.onCreate 之前,能做到早点调入,但也会抢占启动时间。所以实际项目里要控制初始化的总量,别把网络请求这种耗时操作一股脑塞进启动流程。

5. 组件化与 MVVM、微服务、编译效率这些话题的关系

5.1 组件内部最好不要自成一国

组件化只是工程层面的切分,它并没有规定组件内部用什么架构。很多团队在拆完模块后发现,整个工程看起来边界分明,但每个组件里还是老一套:Activity 又臭又长,数据层和 UI 层混在一起。组件化的收益只剩“能编译快点”,开发体验没有质变。所以组件化落地最好和职责分层一起做。理想情况下,每个组件内部可以继续采用 MVVM:Activity/Fragment 只负责视图和交互,ViewModel 处理页面状态,Repository 负责数据。

关键点是 Repository 的位置。如果 Repository 只被一个组件使用,放组件内部没问题;如果多个组件都要访问同一份业务数据,比如用户信息,Repository 或对应的存储逻辑要下沉到基础库,通过接口暴露。跨组件共享状态也可以考虑用共享 ViewModel,但这要求 ViewModel 定义在基础库,并且两个 Fragment 的 Activity 是同一个宿主。否则还是用服务接口或者事件通知更稳。

5.2 组件化和微服务、分布式不是一回事

热搜里经常能看到“微服务架构”和“分布式架构”跟 Android 一起出现,但 Android 组件化跟后端微服务只是名字有点像,解决问题的层次完全不同。微服务是把一个后端系统拆成多个独立部署的服务,通过网络通信协同;分布式则强调多节点、多进程、数据同步。Android 组件化所有模块最终都跑在同一个 App 进程里,组件之间调用是内存级的方法调用,不是网络调用,也没有独立的进程和部署单元。

所以用“微服务”来类比组件化,可以帮助理解“服务自治”的思想,但不要真的照搬后端的服务治理方案。比如引入跨进程通信来解决组件间调用,会引入序列化、进程生命周期、内存开销等一系列新问题,对绝大多数 App 来说没有必要。组件化要做的是在编译期让模块互相不可见,在运行期通过注册表、路由等手段协作,比微服务的粒度更轻,目标也不是独立部署,而是并行开发和降低单模块复杂度。

5.3 组件化之后的测试与构建提速

拆组件之后,最直接的感受是全量编译可能差不多,但增量编译明显变快:只改一个组件时,Gradle 只需要重新编译该组件和它下游依赖,壳 App 打包阶段大部分都是增量。配合 Gradle 并行构建和配置缓存,一个中型项目全量编译从两分钟降到一分半、改动单模块在几十秒内完成,都是能实现的。如果还觉得慢,可以检查是不是每个组件都开了minifyEnabled,或者组件依赖了太多api,导致不必要的重新编译范围扩大。

测试方面,组件化之后单元测试更容易聚焦。你可以只针对某个组件的 ViewModel、Repository 写测试,不牵动其他模块。配合testOptions.unitTests.isReturnDefaultValues = true和 MockWebServer 之类的工具,数据层测试基本能闭环。UI 测试依然需要壳 App 或者专门的测试 target,但至少不再要求每个改动都跑全量回归。组件独立调试还能让你快速验收某个业务模块的改动,不用每次把整个 App 跑起来,这点对移动端开发效率提升非常明显。

6. 落地组件化的时间节奏和我的实战体会

6.1 理性设定目标:先拆试点,再逐步铺开

组件化改造不是周末加个班就能完成的,它本质上是一个跨版本的工程演进。我建议的节奏是:第一个版本只做两件事,搭好基础库和壳 App 的骨架,再选一个边界最清晰、独立性最强的业务模块试点拆分。比如个人中心这种“自己玩得转”的模块,把它从主工程抽出去,作为第一个吃螃蟹的组件。抽的过程会自然暴露出很多隐藏耦合,这些耦合正好整理进你的基础库和接口清单。

第二个版本再做第二个业务组件,并且开始引入路由和服务注册表,让新组件和旧业务之间通过标准方式通信。到第三个版本,再考虑把多个业务组件都拆出来,统一 debug 模式。按这个节奏,每个版本都能回归、能发版,而不是憋一个巨型分支重构半年。团队的心理压力会小很多,风险也逐步释放。我见过最失败的做法是一口气把全部模块拆完,结果发版时线上问题根本没法快速定位,因为版本节奏完全被打乱了。

6.2 三个我后悔没早点做的事

第一件,没有早点统一资源命名规范。当时急着拆模块,用的是公司老工程的资源,activity 叫activity_main,drawable 叫shape_bg,等到拆完两个组件开始联调时,各种资源互相覆盖,查得痛苦。如果一开始就在基础库推行resourcePrefix并在 CI 上加资源命名校验,后面会省很多回头工。第二件,没有早点把路由表作为文档维护。路由路径散落在代码注解里,团队新同学难以覆盖全局,经常是查源码才知道/order/detail在哪个模块。后来我把所有路径按模块归类写到一个Routes.md,code review 时要求新路由必须同步更新,这个文档成了团队的公共地图。第三件,没有早点建设依赖检查工具。Gradle 的implementation和api用错了地方,短期内发现不了,直到某天组件想要替换内部库时,才发现它的依赖被上层到处引用。

我现在的习惯是:在 CI 脚本里加一个依赖检查任务,比如用./gradlew :app:dependencies定期生成报告,同时用 Lint 检查模块间的依赖方向,遇到违规直接失败。这套流程看起来费事,但长期维护成本比“人工盯代码”低得多。

6.3 组件化的“度”:别为了架构而架构

组件化做到一定程度,会发现新的问题也可能从组件化本身长出来。比如组件之间的边界太细,一个功能横跨五六个模块,改个按钮要同时动四五个工程;模块太多后,每次打开 Android Studio 同步项目都要跑好几轮 task;路由跳转的参数校验开始变得困难。这些都在提醒我们:组件的粒度不是越细越好。

以我现在的经验,一个 Android 工程里,业务组件的数量控制在 6 到 10 个左右是比较舒服的区间。组件并不是越小越好,而是要对应真实的产品边界和团队分工。如果团队只有两个 Android 开发,拆八个业务组件基本就是在给自己找麻烦。组件化的最终目的是让开发更高效,不是为了在方案评审会上显得专业。先把单体整理干净,再逐步拆;拆完一个模块就复盘一次依赖和构建速度,敢用数据说话,而不是看架构图是否好看。最后说句实在话,组件化带来的收益不会在拆完第一个模块那天体现,而是体现在你连续迭代两个月后,改一个孤立模块而生病的概率明显变低、编译时间明显变短的时候。这口气,值得慢慢等。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询