该项目大概是从 2015 年开始迭代到现在的 v2.11.1,其中主要的三个大的模块ia(incomeapp)ot(orangetravel)和oh(orangehealth)分别有三个团队维护,我司在 2021 年开始负责并重构了ia模块也就是现在的nia,2022 年 10 月份开始由我司开始重构整个 app,把目前的 MVC 的开发模式重构为基于 Kotlin 的 MVVM 模式
概要
新版本的重构重点是把旧版的 MVC 架构重构当前比较流行的基于 Google Jetpack
的 MVVM 架构
经典的 Android MVVM 架构图:
重构周期
项目重构周期为三个月(初定),期间的大致规划如下:
- 9 月份开始接手搭建基础框架并整理重构路线
- 10 月份把现有业务逻辑代码改成 MVVM 的实现方式并添加 Unit Test
- 11 月份根据新的 design 图重构 UI 部分并把主体业务逻辑跑通
- 12 月份 QA 上手测试和开发修复 bug
注: 以上是初步计划,后续很大概率会有改动,影响有前期对项目的认知不足导致的工期的延长、人员的增减等不确定因素
重构要点
迁移方式
- 直接移动类到相应的
module下然后重命名,这种方式是涉及更改的类会比较多 - 新建一个在功能上优化后的类,(可参考 LocalStorage 的实现)在旧版的实现上请加上 Deprecated 注解,以此让团队的其他成员了解此类有新的实现
App 模块化后的架构
目录结构如下:
1 | app |
基于 MVVM 架构重构后的项目结构图:

注:如果在各模块的
build.gradle里用api来引用其他模块,那么引用关系大致如上图,但是使用api会导致 Gradle 编译变慢,所以现在项目里都是用implementation来引用其他模块和第三方库
项目结构模块说明:
| 模块名 | 作用 | 说明 |
|---|---|---|
| :app | v2.11.1 及以前的代码都在里面,包括网络、本地存储、Firebase Config、事件统计、业务逻辑、UI 等全部功能 | 随着 app 业务逐渐增大、代码逐渐复杂,单 Module 工程显然不足以应对,借着这次 MVVM 重构的机会,把各个功能代码迁移到独立的 module 里去,其中包括 nia(ia)、ot、oh 等主要功能模块 |
| :insurance | 重构后的主模块,insurance app 的一系列设置和 feature 模块交互提供路由跳转等实现 | 重构后的主模块相对 app 模块来说就像是一个壳,主要的功能都迁移到一个独立的 library 模块中,除了一些必要的代码实现 |
| :feature:home | 旧版nia模块的主要内容都会迁移到此 module,已知的有 dashboard、account 等功能 |
待定 |
| :feature:auth | 旧版nia模块里的 login、register 和 OTP verify 等页面,这些页面与其他 feature 交互不频繁属于一次性交互 |
待定 |
| :feature:health | 旧版oh模块的页面迁移到此 module,包括 challenge、rewards、friends 和 earn points 等功能 |
待定 |
| :feature:travel | 旧版ot模块的页面迁移到此 module |
待定 |
| :feature: … | 模块名待定,如果觉得以上 feature 划分不合理或者深入了解nia、ot和oh后可以再创建一个单独的 module |
划分独立 feature 模块的原则是 module 内的页面相对内聚,除了入口页面外其他的页面与其他 feature 模块并无交互 |
| :core:common | 为各个 feature 模块提供基础通用的实现,定义 feature 模块路由交互的接口 |
提供各种 base 类,其中 BaseFragment 中提供 UI 上通用的业务逻辑处理 |
| :core:storage | 迁移旧版 database、mmkv、security-crypto 等本地存储 | 禁止 room 允许主线程查询的设置、封装基于 mmkv 的用户信息存储,避免太过分散的情况,添加 unit test,迁移旧版的 SharedPreference 的实现到此 module 是为了方便做 unit test,后续考虑加入内存缓存的实现包括旧版中 otpToken 等一次性的值 |
| :core:network | 基于 Retrofit、Moshi 和 kotlin flow 的网络请求模块 | 摈弃了旧版的基于 Volley 的网络请求实现,同时兼容了 Glide 加载 income 图片需要添加 header 的操作 |
| :core:config | 获取 Firebase Remote Config 模块,主要封装了获取 config 的逻辑 | 包括 config 的获取、缓存和容灾处理等逻辑,向外提供接口,逻辑实现主要在 module 内部 |
| :core:analytics | 事件统计模块(待完善) | 目前事件统计功能实现太过分散,没有形成统一管理 |
| :core:widget | 自定义控件模块(待完善) | 待新设计图出来后可重新封装或者在旧版的基础上更改迁移过来 |
| :core:model | 实体类模块,包括网络请求和响应、事件统计和描述页面数据等 model | 主要从旧版的 model 中迁移或封装而来,必要时可更改类名使其更简洁易读 |
| :core:utils | 工具类模块,为其他模块提供通用的工具类包括各种 utils 和 extension 类 | 内部也迁移了旧版的一些代码,主要是为了向其他的模块的 unit test 提供支持,在后续迭代几个版本后确认后可安全删除 |
更多内容可以参考掘金这篇关于 模块化 的文章, 重构后的代码里有很多的借鉴, 还有官方 github 的 sample 工程
多 Module 交互模型
官方提供的 ViewModel 的作用域

数据交互模型

参考 用 Kotlin Flow 解决 Android 开发中的痛点问题
技术选型
- Gradle 构建 - ktx 配合 MavenPom 参考将构建配置从 Groovy 迁移到 KTS
- Hilt-Android - 注解框架 参考Hilt 使用详解
- Navigation - 路由框架 官方介绍
- Kotlin Flow & Channel - Flow、StateFlow、SharedFlow、ChannelFlow 等
- MVI 架构 - 解决 ViewModel 和 View 层通过 LiveData 通信的一些问题 参考这边文章
- Jetpack 组件 - Lifecycle、ViewModel、Room、WorkManager、LiveData 等
- 网络请求框架 - Retrofit + Moshi + Okhttp
- 日期处理 - JodaTime
- Log 处理 - Timber
- 图片加载 - Glide