包含多个 Gradle 模块的项目称为多模块项目。本指南包含有关开发多模块 Android 应用的最佳实践和推荐模式。
代码库不断变大的问题
在不断变大的代码库中,可扩缩性、可读性和整体代码质量通常会随着时间的推移而降低。这是因为代码库在不断变大,而其维护者未采取积极措施来保持易于维护的结构。模块化是一种行之有效的代码库构建方法,可帮助改善可维护性并避免此类问题。
什么是模块化?
模块化是按多个松散耦合的独立部分整理代码库的做法。每个部分都是一个模块。每个模块都是独立的,并且都有明确的用途。通过将问题划分为更小、更易于解决的子问题,您可以降低设计和维护大型系统的复杂性。
![](https://developer.android.google.cn/static/topic/modularization/images/1_sample_dep_graph.png?authuser=8&hl=hu)
模块化的优势
模块化具有众多优势,但核心都是提高代码库的可维护性和整体质量。下表总结了模块化的主要优势。
优势 | 摘要 |
---|---|
可重用性 | 模块化可支持在同一基础上共享代码并构建多个应用。模块实际上就是构建块。应用应为其各项功能的总和,而这些功能按单独的模块进行划分。特定模块提供的功能不一定会在特定的应用中实现。例如,:feature:news 可以是完整版本变种和 Wear 应用的一部分,但不是演示版本变种的一部分。 |
严格控制可见性 | 借助模块,您可以轻松控制向代码库的其他部分公开哪些内容。您可以将除公共接口以外的所有内容标记为 internal 或 private ,以防止在模块外部使用这些内容。 |
自定义分发 | Play Feature Delivery 使用了 app bundle 的多种高级功能,让您可以按条件或按需分发应用的某些功能。 |
上述优势只能通过模块化代码库实现。采用其他方法也可实现以下优势,但模块化可以帮助您进一步强化这些优势。
优势 | 总结 |
---|---|
可伸缩性 | 在紧密耦合的代码库中,单项更改可能会触发看似不相关的代码部分的级联更改。适当模块化的项目将遵循关注点分离原则,因此可限制耦合。这样一来,贡献者将拥有更大的自主权。 |
所有权 | 除了实现自主权外,模块还可用于实现问责制原则。可以由一个专门的所有者来负责为模块维护代码、修复 bug、添加测试以及查看更改。 |
封装 | 封装意味着代码的每个部分都应尽可能少地了解其他部分。隔离的代码更易于阅读和理解。 |
可测试性 | 可测试性是指测试代码的轻松程度。可测试代码是指可以轻松单独测试组件的代码。 |
构建时间 | 某些 Gradle 功能(如增量构建、构建缓存或并行构建)可以利用模块化来提升构建性能。 |
常见误区
代码库的粒度是指其模块化程度。更细粒度的代码库包含更多、更小的模块。在设计模块化代码库时,您应当决定粒度级别。为此,请考虑代码库的大小及其相对复杂度。过于精细化的设计会增加开销负担,而过于粗略又会降低模块化的优势。
下面列出了一些常见误区:
- 过于精细:每个模块都会产生一定的开销,包括增加构建复杂度以及引入样板代码。复杂的 build 配置会导致难以在模块之间保持配置一致。过多的样板代码会导致代码库冗长累赘,难以维护。如果开销抵消了可伸缩性方面的改进,则应考虑整合某些模块。
- 过于粗略:相反,如果模块过大,最终可能会产生另一个单体式模块,失去模块化的优势。例如,在小项目中,将数据层放到单一模块中是没有问题的。但随着模块变大,您可能需要将代码库和数据源拆分为独立的模块。
- 过于复杂:构建模块化项目并非总是明智的做法。代码库的大小是一项决定因素。如果您预计项目不会变大到超过某个特定阈值,则不必考虑可伸缩性和构建时间。
我是否适合采用模块化方法?
如果您需要实现可重用性、严格控制可见性或使用 Play Feature Delivery,则有必要采用模块化方法。如果您尚未采用模块化方法,但希望改善可扩缩性、所有权、封装或构建时间,那么模块化是一种值得考虑的方法。
示例
- Now in Android - 功能完备的模块化 Android 应用。
- 多模块架构示例