架构总览
SumTea_Android 是一款基于 Kotlin 语言与 Jetpack 组件构建的 Android 客户端应用,采用 MVVM 架构模式,通过组件化与模块化拆分实现业务解耦与复用。项目整合了 Navigation、Lifecycle、DataBinding、LiveData、ViewModel 等现代 Android 开发技术栈,并使用协程+Flow+Retrofit+OkHttp 实现响应式网络请求,通过 Room 数据库与 mmkv 实现数据持久化与缓存管理。
整体架构设计
架构模式与核心原则
项目采用 MVVM(Model-View-ViewModel)架构模式,遵循 Google 推荐的应用架构设计原则。在该架构中,ViewModel 仅负责数据的存储与 UI 状态管理,所有数据加载操作由 Repository 层完成,实现了数据层与表现层的彻底分离。通过 Room 数据库实现本地数据缓存,在无网络或弱网环境下优先展示缓存数据,提升用户体验(README.md:12-24)。
组件化与模块化策略
项目通过组件化与模块化拆分实现代码解耦与功能复用。使用阿里巴巴开源的 ARouter 路由框架实现模块间通信,各业务模块可独立开发、测试与部署。整体工程包含 APP 壳工程、业务模块(mod_main、mod_user、mod_login、mod_search、mod_video)以及基础库(lib_framework、lib_common、lib_network 等)三个层次(README.md:12-24)。
技术栈选型
核心技术栈包括:
- UI 层:Jetpack Navigation、DataBinding、LiveData
- 网络层:协程+Flow+Retrofit+OkHttp
- 数据层:Room 数据库、mmkv 键值存储
- 媒体层:ExoPlayer 视频播放、Glide 图片加载
- 路由层:ARouter 模块间通信
正在加载图表渲染器...
架构图说明:
- APP 壳工程:作为应用入口,负责环境配置、签名混淆及业务模块集成(README.md:28-30)
- 业务模块层:包含 5 个独立业务模块,通过 ARouter 实现模块间通信
- 基础库层:提供通用 Base 类、工具类及网络请求封装,被所有业务模块依赖
- 支撑库层:提供启动器、Banner、图片加载、数据库等专项功能支持
模块划分与职责
业务模块详解
mod_main 首页模块
职责边界:负责应用主界面的四个 Tab(首页、分类、体系、我的)及其子页面管理,不涉及用户认证与视频播放等独立功能。
入口与关键 API:
- Tab 导航:通过 Navigation 组件管理四个 Tab 的切换
- 首页 Banner:轮播图展示
- 视频列表:短视频列表入口
- 文章列表:项目文章展示
关键数据结构:
- Banner 数据模型:包含图片 URL、跳转链接等字段
- 文章列表数据:分页加载的文章实体集合
交互方式:通过 Navigation 组件实现 Tab 切换,通过 ARouter 跳转至其他业务模块(README.md:31-36)
mod_user 用户模块
职责边界:管理用户个人设置、账户安全及隐私政策,不涉及登录注册流程。
核心功能:
- 个人信息管理:头像、姓名、手机号码设置
- 隐私政策条款展示
- 版本信息查看与 App 更新
- 缓存清理功能
- 用户退出登录(README.md:37-43)
mod_video 视频模块
职责边界:专注于短视频播放功能,保证全局只有一个播放器实例,不涉及视频推荐算法。
关键实现:
- RecyclerView 实现防抖音短视频列表
- ExoPlayer 播放器封装
- RotateNoteView 旋转音乐盒动画(README.md:52-55)
基础库封装
lib_framework 框架基础库
职责边界:提供所有业务模块通用的基础类与工具类,不包含具体业务逻辑。
核心组件:
- Base 基类:BaseActivity、BaseFragment 等
- Ext 扩展函数:Kotlin 扩展函数集合
- Loading 加载框:统一的加载状态展示
- LogUtil:日志打印工具
- Manager 管理类:各类资源管理器
- TipsToast:吐司提示工具
- 带删除按钮的 EditText 组件(README.md:56-64)
lib_network 网络库
职责边界:封装网络请求能力,提供统一的 API 调用接口与错误处理机制。
核心组件:
- Api 接口类:Retrofit 接口定义
- 错误相关类:统一的错误处理模型
- Flow 扩展类:协程 Flow 封装
- Http 拦截器:日志、缓存、重试等拦截器
- BaseViewModel & BaseRepository:协程网络请求封装
- OkHttp 和 Retrofit 配置(README.md:71-78)
lib_common 通用组件库
职责边界:提供跨模块共享的组件、常量及实体类。
核心组件:
- 二次封装的 Banner 组件
- 常量类:全局常量定义
- 实体 Bean:共享数据模型
- 组件化通信的 Provider 和 IService
- 通用 View 组件(README.md:65-70)
应用初始化流程
启动优化策略
项目采用异步任务启动器(TaskDispatcher)实现应用启动优化。通过将初始化任务按优先级、依赖关系进行编排,利用线程池并行执行,显著减少应用启动时间(app/src/main/java/com/sum/tea/SumApplication.kt:41-65)。
初始化任务编排
kotlin1// 1. 启动器初始化 2TaskDispatcher.init(this) 3 4// 2. 创建 dispatcher 实例 5val dispatcher: TaskDispatcher = TaskDispatcher.createInstance() 6 7// 3. 添加任务并且启动任务 8dispatcher.addTask(InitSumHelperTask(this)) 9 .addTask(InitMmkvTask()) 10 .addTask(InitAppManagerTask()) 11 .addTask(InitRefreshLayoutTask()) 12 .addTask(InitArouterTask()) 13 .start() 14 15// 4. 等待,需要等待的方法执行完才可以往下执行 16dispatcher.await()
关键任务说明(app/src/main/java/com/sum/tea/SumApplication.kt:50-64):
- InitSumHelperTask:应用辅助类初始化
- InitMmkvTask:MMKV 键值存储初始化
- InitAppManagerTask:应用管理器初始化
- InitRefreshLayoutTask:下拉刷新组件初始化
- InitArouterTask:ARouter 路由框架初始化
生命周期管理
前后台切换监听
通过 AppFrontBack 注册应用前后台切换监听,实现应用状态感知:
kotlin1private fun appFrontBackRegister() { 2 AppFrontBack.register(this, object : AppFrontBackListener { 3 override fun onBack(activity: Activity?) { 4 LogUtil.d("onBack") 5 } 6 override fun onFront(activity: Activity?) { 7 LogUtil.d("onFront") 8 } 9 }) 10}
(app/src/main/java/com/sum/tea/SumApplication.kt:77-90)
Activity 生命周期监听
注册 ActivityLifecycleCallbacks 监听所有 Activity 的生命周期事件,通过 ActivityManager 管理 Activity 栈:
kotlin1private fun registerActivityLifecycle() { 2 registerActivityLifecycleCallbacks(object : ActivityLifecycleCallbacks { 3 override fun onActivityCreated(activity: Activity, p1: Bundle?) { 4 ActivityManager.push(activity) // Activity 入栈 5 } 6 override fun onActivityDestroyed(activity: Activity) { 7 ActivityManager.pop(activity) // Activity 出栈 8 } 9 // ... 其他生命周期回调 10 }) 11}
(app/src/main/java/com/sum/tea/SumApplication.kt:92-120)
MultiDex 优化
在 attachBaseContext 阶段,通过 CPU IO 线程池异步执行 MultiDex.install,避免主线程阻塞:
kotlin1override fun attachBaseContext(base: Context?) { 2 super.attachBaseContext(base) 3 AppExecutors.cpuIO.execute(Runnable { 4 MultiDex.install(base) 5 }) 6}
(app/src/main/java/com/sum/tea/SumApplication.kt:28-34)
数据流与调用链
MVVM 数据流架构
正在加载图表渲染器...
数据流说明:
- View 层:通过 DataBinding 实现 UI 与数据的双向绑定,观察 LiveData 的变化
- ViewModel 层:持有 LiveData,暴露数据给 View 层,不持有 View 的引用
- Repository 层:负责数据加载逻辑,决定从本地缓存或网络获取数据
- 数据源层:Room 数据库提供本地持久化,Retrofit 提供网络请求能力
网络请求调用链
正在加载图表渲染器...
调用链说明:
- View 层通过调用 ViewModel 的方法触发数据请求
- ViewModel 将请求委托给 Repository 层处理
- Repository 优先检查本地缓存(Room 或 mmkv)
- 若缓存有效则直接返回,否则发起网络请求
- 网络请求通过 Retrofit 执行,响应数据更新到本地缓存
- Repository 将数据发送给 ViewModel,ViewModel 通过 LiveData 通知 View 层更新
核心设计决策与取舍
1. MVVM 架构选型
选择理由:
- LiveData 与 Lifecycle 组件天然集成,自动管理生命周期
- ViewModel 在配置变更时保留数据,避免重复加载
- DataBinding 减少样板代码,提升开发效率
- 符合 Google 官方推荐架构,便于团队协作与维护
已知限制:
- DataBinding 在复杂布局中可能影响编译速度
- LiveData 的不可变性要求额外的转换操作
2. 组件化设计
选择理由:
- 业务模块独立开发与测试,降低耦合度
- 支持模块级别的代码复用
- 便于后续功能扩展与重构
已知限制:
- 模块间通信需要通过 ARouter,存在一定的性能开销
- 需要维护路由表,增加管理复杂度
3. 协程+Flow 网络请求
选择理由:
- 协程提供轻量级并发能力,避免回调地狱
- Flow 支持响应式数据流,便于数据转换与组合
- 与 Retrofit 无缝集成,代码简洁易读
已知限制:
- 需要理解协程的作用域与调度器概念
- 异常处理需要额外注意
4. Room 数据库
选择理由:
- 编译时 SQL 语法检查,减少运行时错误
- 支持 LiveData 与 Flow 集成,自动更新 UI
- 类型安全的数据库访问
已知限制:
- 复杂查询需要编写原生 SQL
- 数据库迁移需要额外处理
5. TaskDispatcher 启动优化
选择理由:
- 支持任务优先级与依赖关系配置
- 利用线程池并行执行,减少启动时间
- 提供 await 机制确保关键任务完成
已知限制:
- 任务编排需要仔细设计,避免循环依赖
- 线程池配置需要根据设备性能调整
技术选型表格
| 技术 | 用途 | 选型理由 | 替代方案 |
|---|---|---|---|
| Kotlin | 开发语言 | 简洁安全,与 Java 互操作,协程原生支持 | Java |
| Jetpack Navigation | 导航管理 | 官方推荐,支持 Fragment 事务自动管理 | FragmentManager |
| DataBinding | UI 绑定 | 减少样板代码,支持双向绑定 | ViewBinding |
| LiveData | 数据观察 | 生命周期感知,自动取消订阅 | RxJava |
| ViewModel | UI 状态管理 | 配置变更时保留数据,与 LiveData 配合 | 自定义 Presenter |
| Retrofit | 网络请求 | 类型安全,支持多种转换器 | Volley |
| OkHttp | 网络层 | 高性能,支持拦截器与缓存 | HttpURLConnection |
| Room | 数据库 | 编译时检查,支持 LiveData | SQLite |
| mmkv | 键值存储 | 高性能,支持多进程 | SharedPreferences |
| ExoPlayer | 视频播放 | 支持多种格式,扩展性强 | MediaPlayer |
| Glide | 图片加载 | 自动缓存,支持 GIF | Picasso |
| ARouter | 路由框架 | 支持依赖注入,拦截器机制 | DeepLink |
| TaskDispatcher | 启动优化 | 支持依赖关系,线程池管理 | 自定义线程池 |
模块依赖关系
正在加载图表渲染器...
依赖关系说明:
- 单向依赖:应用层依赖业务层,业务层依赖核心层,核心层依赖支撑层
- 模块隔离:业务模块之间无直接依赖,通过 ARouter 实现通信
- 核心层复用:lib_framework、lib_common、lib_network 被所有业务模块共享
- 支撑层独立:各支撑库可独立使用,无横向依赖
关键配置与启动流程
Application 启动流程
正在加载图表渲染器...
启动流程说明(app/src/main/java/com/sum/tea/SumApplication.kt:41-65):
- attachBaseContext 阶段:异步执行 MultiDex.install,避免主线程阻塞
- onCreate 阶段:
- 注册前后台切换监听
- 注册 Activity 生命周期监听
- 初始化 Toast 工具
- TaskDispatcher 初始化:
- 初始化启动器
- 创建实例
- 添加异步任务
- 启动任务并等待完成
模块间通信机制
通过 ARouter 实现模块间通信,各业务模块通过 @Route 注解声明可访问的页面或服务,其他模块通过 ARouter 路由表进行跳转或服务调用。lib_common 模块中定义了组件化通信的 Provider 和 IService 接口,作为模块间通信的契约(README.md:65-70)。
