截至2026年,Now in Android(以下简称 NiA)依然是由 Google 官方维护、最能代表“现代 Android 应用架构”的标杆项目,GitHub 星标已突破 20K。
它不仅系统性地展示了 Jetpack 全家桶的最佳实践,更关键的是,提供了一整套面向中大型项目的可落地工程方案——涵盖模块化设计、分层架构、自动化测试、性能分析、代码提交、风格检查以及团队协作等核心环节,是 Android 应用开发者的必学项目。
本系列文章专为 Android 应用开发者打造,将以抓大放小的模式深入解析 Now in Android 的设计精髓,全系列共八章。
- 《Now in Android 现代应用开发实践(一):模块化设计》
- 《Now in Android 现代应用开发实践(二):架构设计(data+domain)》
- 《Now in Android 现代应用开发实践(三):架构设计(UI)》
- 《Now in Android 现代应用开发实践(四):构建逻辑》
- 《Now in Android 现代应用开发实践(五):代码规范》
- 《Now in Android 现代应用开发实践(六):质量保障体系》
- 《Now in Android 现代应用开发实践(七):Benchmark 性能测试》
- 《Now in Android 现代应用开发实践(八):Baseline 性能优化》
本文作为开篇,将结合 Android 官方模块化指南,重点解读 NiA 的模块化设计思路,帮助你厘清以下关键问题:
- 为什么需要模块化?
- NiA 到底如何划分模块?
- 它遵循了 哪种 官方推荐的模块化模式?
- 哪些设计决策值得在实际项目中借鉴?
通过本文,你将获得一套可复用的模块化思维框架,为构建健壮、可维护的现代 Android 应用打下坚实基础。
一、为什么绕不开模块化?
Android官方模块化指南把好处总结得很直接:
- 构建速度:增量编译、并行执行、缓存命中率大幅提升
- 可维护性: 关注点分离、降低耦合、修改一处不影响全局
- 团队协作: 模块可以分配owner,减少代码冲突
- 可测试性: 模块粒度测试更容易Mock、更快运行
- 可重用性: 核心功能模块可复用到多个App/变体/Wear/TV
- 功能按需交付(Dynamic Feature)潜力
- 封装与可见性控制: 利用
internal真正隐藏实现细节
简单总结就是,当项目超过2-3万行代码、超过5-8人团队时,模块化几乎是唯一能把复杂度控制住的手段。
二、主流模块化方案分析
在 Android 架构设计中,常见的模块组织模式主要有三种:纯分层、纯按功能划分,以及分层与功能混合的模式。
1.纯分层模式
-
核心思路:按照技术职责纵向划分,典型的层级顺序为 data → domain → feature → app。
-
优点:这种结构清晰简单,天然契合 MVVM 架构思想,易于上手。
-
缺点:不同业务功能之间容易产生耦合,因为它们共享同一套分层结构,修改一个模块可能影响其他模块。
-
适用场景:适合中小型项目,团队规模不大、业务复杂度较低时使用效果较好。
2.纯按功能划分模式
-
核心思路:以业务功能为单位横向组织代码,每个功能模块(如“登录”、“个人中心”、“订单”)几乎形成一个独立闭环,包含自己的数据、领域逻辑和 UI 层(类似组件化)。
-
优点:这种方式实现了极高的模块独立性,非常适合多团队并行开发,并支持动态下发或独立发布特定功能。
-
缺点:其代价是容易造成重复代码(比如多个模块各自实现相似的网络请求或工具类),且全局数据层难以统一设计和维护。
-
适用场景:它主要适用于超大型应用,尤其是需要多团队协作、支持模块化动态交付的场景。
3.分层 + 功能混合模式
-
核心思路:将架构分为两大部分:底层是高度抽象、通用的核心层(包含共享的数据源、工具类、基础组件等),上层则是按功能划分的独立业务模块。
-
优点:既保证了通用能力的复用,又赋予各业务模块足够的自治性。它在可维护性、可扩展性和团队协作效率之间取得了良好平衡
-
缺点:初期架构搭建和理解成本略高,需要团队有一定经验,
-
适用场景:中大型生产项目主流选择
Now in Android 采用的就是第三种“分层 + 功能混合”模式,而且做了非常有特色的细化 - Feature模块内部api / impl 双层分离。
三、NiA 模块化结构解析
:app # 应用入口(脚手架 + 导航)
│
├─ :feature
│ ├─ :foryou
│ │ ├─ :api # 只放导航key和导航扩展函数
│ │ └─ :impl # 真正的Screen、ViewModel、UI逻辑
│ ├─ :interests
│ ├─ :topic
│ └─ ... (其他业务功能)
│
├─ :core
│ ├─ :data # 统一对外数据仓库(Repository)
│ ├─ :network # Retrofit + 数据源
│ ├─ :database # Room
│ ├─ :datastore # Preferences DataStore
│ ├─ :model # 纯Kotlin 数据类(跨模块共享)
│ ├─ :ui # 复合UI组件(依赖model和data)
│ ├─ :designsystem # 基础UI组件 + 主题 + 图标(纯Compose)
│ ├─ :common # 通用工具、Dispatchers、Result封装等
│ └─ :testing # 测试桩、TestRunner等
│ └─ ...
│
├─ :sync # 工作管理器同步任务(同样属于应用的业务逻辑)
├─ :benchmark # 宏基准测试
└─ :app-NiA-catalog # 静态展示App内的组件,是一个独立应用
1.App 模块:应用的 “粘合剂”
App 模块是整个应用的入口,属于android-application类型,核心职责是整合所有模块,提供应用级脚手架,不承担具体业务逻辑。
核心内容:
- 包含
MainActivity、NiAApp等应用级入口类,以及全局导航配置(如NiANavHost实现应用级导航、TopLevelNavItem配置底部导航栏);
依赖规则:
- 依赖所有功能(Feature)模块和所需的核心(Core)模块,是依赖链的 “顶端”。
2.功能(Feature)模块:业务逻辑的载体
Feature 模块是应用的业务核心,每个模块聚焦一个具体功能(如 “为你推荐”“兴趣管理”“主题详情”),遵循 “单一职责” 设计。
NiA 对 Feature 模块做了精细化拆分 —— 每个 Feature 模块拆分为两个子模块:
api子模块:仅包含导航键(如TopicNavKey)和导航函数(如Navigator.navigateToTopic),用于对外暴露跳转能力;
impl子模块:包含功能的所有核心逻辑(UI 界面、ViewModel、业务处理等),是功能的实际实现层。
依赖规则:
-
api子模块:不依赖其他 Feature 的api/impl子模块,仅依赖 Core 模块; -
impl子模块:仅可依赖其他 Feature 的api子模块(用于跨功能跳转),且仅依赖所需的 Core 模块; -
核心原则:避免 Feature 模块间的直接耦合,通过
api层实现 “最小化依赖”。
3.核心(Core)模块:通用能力的封装
核心模块是通用的库模块,包含辅助代码和需要在应用其他模块间共享的特定依赖项。这些模块可以依赖于其他核心模块,但不应依赖于功能模块或app模块。
| 模块路径 | 主要功能 / 职责 | 典型类 / 文件示例 | 备注说明 |
|---|---|---|---|
| :core:model | 存放应用中通用的纯Kotlin数据模型类(无Android依赖) | NewsResource, Topic, Episode, Author | 纯jvm module,最底层模型 |
| :core:database | 使用Room实现本地数据库,包括数据库定义、Entity、Dao和迁移 | NiADatabase, NewsResourceDao, DatabaseMigrations | Room数据库核心 |
| :core:datastore | 使用Preferences DataStore存储用户偏好设置(轻量级KV存储) | NiAPreferences, UserPreferencesSerializer | 常用于用户偏好、首次启动标志等 |
| :core:datastore-proto | DataStore的protobuf定义文件(独立出来方便多平台复用) | .proto 文件(如user_preferences.proto) | 一般不直接使用,仅供datastore依赖 |
| :core:network | 网络层实现,包括Retrofit接口定义、数据源、拦截器等 | RetrofitNiANetworkApi, NiANetworkDataSource | 远程数据源核心 |
| :core:data | 数据层统一对外接口(Repository模式),聚合本地+远程数据源,提供业务所需数据 | TopicsRepository, NewsRepository, UserDataRepository | 最常用的数据仓库入口 |
| :core:data-test | 数据层相关的测试桩(fake实现、测试双重实现) | FakeNewsRepository, TestNiANetworkDataSource | 专供单元测试/集成测试使用 |
| :core:ui | 业务相关的复合UI组件(依赖model和data层,能展示真实业务数据) | NewsResourceCard, NewsFeed, TopicGridItem | 区别于designsystem,更偏业务 |
| :core:designsystem | 基础设计系统:主题、颜色、排版、图标、基础Compose组件 | NiATheme, NiAButton, NiAIcons, NiATopAppBar | 类似组件库,可单独预览 |
| :core:common | 通用工具类、扩展函数、跨模块共享的小型工具 | NiADispatchers, Result, Async, DispatcherProvider | 放那些到处都要用的小工具 |
| :core:analytics | 埋点/分析相关接口与实现(目前主要对接Firebase Analytics) | AnalyticsHelper, StubAnalyticsHelper | 可切换真实/空实现,方便测试 |
| :core:testing | 通用测试工具、规则、runner、Hilt测试模块等 | NiATestRunner, TestDispatcherRule, HiltTest | 几乎所有测试模块都会依赖它 |
4.数据同步(Sync)模块
sync: 负责处理后台同步逻辑。它利用 WorkManager 定时或根据触发条件从网络更新数据,并将其持久化到本地数据库中。
NiA采用本地数据优先的架构设计方式,有关架构设计的分析下一章会详细介绍。
5.工程治理与构建逻辑类
这类模块不直接包含业务代码,而是为了管理日益复杂的 Gradle 构建配置。
-
build-logic: 这是 NiA 最核心的构建管理模块。随着模块数量增加,NiA 提取了通用的配置插件(Convention Plugins),用于统一管理各模块的编译 SDK 版本、Compose 配置、Lint 规则和 Hilt 依赖。这样可以避免在几十个模块的build.gradle中重复写相同的配置。 -
spotless: 这是一个代码格式化工具模块。它通过配置特定的规则(如 Kotlin 编码规范、License 头部信息),确保所有开发者提交的代码风格高度统一。在 NiA 中,它通常结合 Git Hooks 或 CI 流程使用。 -
lint: 包含自定义的 Lint 规则。除了 Android 默认的检查外,NiA 开发团队编写了特定的静态代码检查规则,以确保项目遵循特定的架构规范(例如:禁止在某些层级直接引用特定库)。
6.测试与性能分析类
这类模块用于保障应用的质量和运行效率。
-
benchmark: 包含 Macrobenchmark 测试代码。它专门用于测量应用的启动性能和滚动帧率(Jank)。通过这个模块,开发者可以生成 Baseline Profiles 以优化应用的首次运行速度。 -
ui-test-hilt-manifest: 这是一个特殊的辅助模块。由于 Hilt 在进行集成测试时需要一个空的ComponentActivity作为容器,该模块专门提供所需的 Android Manifest 和 Activity 声明,确保测试代码能正常注入依赖,同时不污染生产代码。
7.基础设施与工具类
tools: 存放开发辅助脚本。kokoro: 这是 Google 内部使用的持续集成(CI)配置文件路径。它包含用于在 Google 基础设施上运行构建、测试和发布流程的脚本(类似于公共领域的 GitHub Actions 配置)。app-NiA-catalog: 这是一个独立的“设计系统目录”APP。它不具备新闻浏览功能,而是专门用于展示core:designsystem中定义的所有 UI 组件(如按钮、图标、颜色)。开发者可以通过运行这个 App 快速预览和调试 UI 组件,而无需启动整个主应用。
四、值得借鉴的几个关键决策点
1.什么时候把功能拆成 api / impl 双模块?
当这个功能会被多个其他页面跳转时(例如 topic、bookmark、search 都是常见被跳转目标)
2.core 模块要拆多细?
NiA给出了比较务实的参考:
-
数据层较小时,可以只保留
:core:data -
数据源/仓库变多时,再拆
:network、:database、:datastore -
UI组件较多时,拆
:designsystem(纯公共UI组件) 和:ui(业务UI组件)
3.要不要追求极致模块化?
根据NiA官方的说法: “我们在过度模块化一个小应用 和 展示适用于生产级大型代码库的模式 之间寻找平衡。 ”所以适度模块化才是王道——粒度太细会显著增加构建配置和维护成本。
五、总结与建议
Now in Android 的模块化设计是目前(2026年)Android社区里最值得参考的生产级实践之一。相比其他 Android 示例(如 Todoist 或 Sunflower),NiA 更注重 Compose UI 和模块化架构的深度集成。
NiA采用分层 + 功能混合模式,并通过功能模块 api/impl 分离巧妙地解决了功能间跳转耦合问题,同时保持了核心代码的高度可重用性。
如果你正在/准备做一个中大型项目(预计>10个主要页面、>5人团队协作、生命周期>2年),强烈建议你:
1.先画出模块依赖图(Mermaid/PlantUML/手绘都行)
2.决定核心模块的拆分粒度
3.对于高频被跳转的功能模块,考虑采用 api / impl 分离
4.所有模块都写README + 依赖图(NiA中的依赖关系图由工程脚本自动生成,后续将讲解如何实现)
下一篇文章我们将深入剖析 NiA 的架构设计,敬请期待~
参考资料:
- Android 官方模块化指南:developer.android.google.cn/topic/modul…
- Android 官方模块化模式:developer.android.google.cn/topic/modul…
- Now in Android GitHub 主仓库:github.com/android/now…
本文写作时使用的辅助AI模型:Gemini Pro + Qwen3 Max