项目总览
项目背景与简介
本项目是一个基于 Jetpack Compose 构建的 WanAndroid 客户端应用,旨在通过实战项目展示现代 Android 声明式 UI 开发范式。项目采用 MVI(Model-View-Intent) 架构模式,结合 单 Activity 架构设计,实现了应用内多页面的统一管理与状态流转。
项目核心价值在于探索 Compose 1.0 稳定版本在生产环境中的应用实践。通过将前端框架(如 React)的单向数据流思想引入 Android 开发,项目构建了一个状态可预测、逻辑高度解耦的客户端应用。这不仅降低了 UI 状态管理的复杂度,也为后续功能迭代提供了清晰的代码结构基础。
在功能实现上,项目完整复刻了 WanAndroid 平台的核心业务流程,包括用户登录、首页文章流、体系分类、项目展示及我的个人中心等模块。通过声明式 UI 的特性,界面能够实时响应数据变化,提供流畅的用户体验。
技术栈与依赖配置
项目采用 Kotlin 作为主要开发语言,全面拥抱 Jetpack Compose 生态。核心依赖配置围绕声明式 UI、依赖注入、网络请求及异步数据处理展开。
核心技术栈
| 技术分类 | 技术选型 | 版本/说明 |
|---|---|---|
| UI 框架 | Jetpack Compose | 1.0 稳定版,声明式 UI 工具包 |
| 架构模式 | MVI | 单向数据流架构,强调唯一数据源 |
| 依赖注入 | Hilt | Google 官方推荐的 DI 框架 |
| 网络请求 | Retrofit + OkHttp | RESTful API 请求库 |
| 异步处理 | Kotlin Coroutines & Flow | 协程与响应式流 |
| 图片加载 | Accompanist Coil/Glide | Compose 专用图片加载库 |
| 分页加载 | Paging 3 | 流式分页数据加载 |
| 本地存储 | DataStore | 替代 SharedPreferences 的现代存储方案 |
构建配置与依赖管理
项目在 app/build.gradle 中进行了详细的构建配置。编译 SDK 版本设置为 31,最低支持 SDK 21,目标 SDK 为 31,确保覆盖绝大多数主流设备 (app/build.gradle:11-24)。
在构建特性方面,启用了 compose true 以支持 Compose 编译器插件,并配置了 Kotlin 编译选项以启用 IR 编译器后端 (app/build.gradle:40-46)。
依赖库的选择体现了“Compose First”的原则:
- UI 基础:引入了
compose.ui、compose.material和compose.ui-tooling-preview,提供基础的 UI 组件和预览支持 (app/build.gradle:59-61)。 - 导航与动画:使用
navigation-compose实现页面路由,配合accompanist系列库(如accompanist-pager,accompanist-swiperefresh)补充了 Compose 暂时缺失的常用控件能力 (app/build.gradle:69-86)。 - 架构组件:集成
hilt-android及其 Compose 扩展,实现 ViewModel 的自动注入和依赖管理 (app/build.gradle:88-93)。 - 数据层:使用
Retrofit处理网络请求,Gson进行 JSON 解析,Paging处理列表分页,Datastore处理数据持久化(如 Cookie) (app/build.gradle:95-108)。
应用配置与入口
应用遵循单 Activity 架构,MainActivity 作为应用的唯一入口,承载了所有的 Compose 页面容器。
应用清单配置
在 AndroidManifest.xml 中,应用声明了必要的网络权限(INTERNET 和 ACCESS_NETWORK_STATE)以支持 API 调用 (app/src/main/AndroidManifest.xml:5-6)。
应用类指定为 .MyApp,这通常是初始化 Hilt 依赖注入容器和全局配置的起点 (app/src/main/AndroidManifest.xml:14)。MainActivity 被配置为 LAUNCHER Activity,并使用了 SplashTheme 作为启动主题,以优化应用启动时的视觉体验 (app/src/main/AndroidManifest.xml:16-26)。
应用标识与版本
应用的包名为 com.zj.wanandroid,版本号定义为 1.0 (app/build.gradle:14-18)。这种配置符合标准 Android 应用发布规范,确保应用在设备上的唯一性和可更新性。
架构设计概览
本项目采用 MVI (Model-View-Intent) 架构模式,这是一种受 Redux 启发的单向数据流架构。与传统的 MVVM 相比,MVI 更加强调状态的不可变性和数据流向的唯一性,这与 Compose 的声明式 UI 理念高度契合。
MVI 架构分层
MVI 架构将应用分为三个核心层次,各层职责明确:
- Model (UI State): 不同于 MVVM 中的数据层,MVI 的 Model 主要指 UI 状态。它是一个不可变的数据类,包含了页面渲染所需的所有信息(如加载状态、数据内容、焦点状态等)。
- View: 负责 UI 渲染与用户交互。在 Compose 中,这通常由
@Composable函数实现。View 不直接修改状态,而是通过订阅 Model 的变化来重组界面。 - Intent: 代表用户的操作意图(如点击、输入)。View 将用户操作封装成 Intent 发发给处理层。
核心数据结构定义
为了实现严格的 MVI 模式,项目定义了三种核心数据结构来约束数据流向。以登录页面为例 (README.md:25-54):
-
ViewState: 定义页面的所有状态。
kotlin1data class LoginViewState( 2 val account: String = "", 3 val password: String = "", 4 val isLogged: Boolean = false 5)- 职责: 集中管理页面状态,确保 View 只需订阅一个数据源即可获取所有 UI 信息。
- 关键点: 字段默认值确保了状态的初始安全性。
-
ViewEvent: 定义一次性事件。
kotlin1sealed class LoginViewEvent { 2 object PopBack : LoginViewEvent() 3 data class ErrorMessage(val message: String) : LoginViewEvent() 4}- 职责: 处理非状态类的副作用,如 Toast 提示、页面跳转、弹窗关闭等。
- 关键点: 使用
sealed class限制事件类型,防止事件泛滥。
-
ViewAction (Intent): 定义用户操作。
kotlin1sealed class LoginViewAction { 2 object Login : LoginViewAction() 3 data class UpdateAccount(val account: String) : LoginViewAction() 4 // ... 5}- 职责: 将用户的所有交互行为标准化。
- 关键点: View 层只发出 Action,不直接处理业务逻辑。
MVI 与 MVVM 的对比
MVI 架构在 MVVM 基础上进行了改良,主要区别在于 (README.md:60-67):
- 交互方式约束: MVVM 中 View 可以随意调用 ViewModel 的方法,而 MVI 禁止 View 直接调用 ViewModel 方法,只能通过发送 Intent 驱动状态变化。这使得业务逻辑的触发点更加清晰。
- 状态管理: MVVM 的 ViewModel 中通常包含多个
LiveData/StateFlow,而 MVI 使用唯一的ViewState容器集中管理状态。这减少了模板代码,并避免了状态不一致的问题。
系统架构与数据流
系统模块架构图
下图展示了项目的宏观模块划分及其依赖关系。系统自下而上分为数据层、领域层(业务逻辑)、架构层(MVI 协调)和表现层。
正在加载图表渲染器...
架构图说明:
- 单向数据流: 数据从 Repository 经过 ViewModel 处理后流向 View,View 仅通过 Intent 发送用户操作,不直接修改数据。
- 依赖注入: Hilt 贯穿全局,负责管理 ViewModel、Repository 及其依赖的创建与生命周期。
- 职责分离: Repository 负责协调远程(API)和本地(DataStore)数据源,对上层屏蔽数据获取细节。
关键交互流程
下图展示了用户在登录场景下的核心交互时序,体现了 MVI 架构如何处理用户输入并更新 UI。
正在加载图表渲染器...
交互流程说明:
- 输入处理: 用户的每一次输入都被封装为 Intent 发送给 ViewModel,确保了状态变更的可追溯性。
- 状态驱动 UI: ViewModel 接收到 Intent 后,更新内部的 ViewState,新的状态自动推送到 View 触发重组。
- 副作用处理: 对于登录成功后的跳转或失败的 Toast,通过 ViewEvent 单独处理,避免状态重绘导致的副作用重复触发。
核心模块与实现细节
1. 表现层
表现层由 MainActivity 和各个页面的 Composable 函数组成。MainActivity 作为单 Activity 架构的容器,主要负责初始化 NavHost 和主题配置。
- 职责: 渲染 UI、捕获用户操作、订阅状态。
- 关键实现: 使用
NavHost管理路由图,每个目标对应一个 Composable 页面。页面内部通过viewModel()函数获取 Hilt 注入的 ViewModel 实例,并通过collectAsState()将 Flow 转换为 Compose 的 State 对象。 - 证据:
MainActivity在 Manifest 中被声明为 LAUNCHER (app/src/main/AndroidManifest.xml:16-26)。
2. MVI 协调层
ViewModel 是 MVI 架构的协调中心,负责处理 Intent 并产生新的 ViewState。
- 职责: 接收 View 层的 Intent、调用 UseCase 执行业务逻辑、将结果映射为 ViewState、处理 ViewEvent。
- 关键数据流:
Intent -> ViewModel -> UseCase -> Repository -> Result -> ViewState。 - 状态管理: 使用
StateFlow或LiveData持有 ViewState。对于一次性事件,通常使用SharedFlow或在 Channel 中发送。 - 证据: README 中详细定义了
LoginViewState和LoginViewAction的结构 (README.md:30-53)。
3. 数据层
数据层负责数据的获取与持久化,通过 Repository 模式统一数据源。
- 职责: 提供纯净的数据给上层,屏蔽数据来源(网络或缓存)。
- 网络请求: 使用 Retrofit 定义 API 接口,结合 Gson 进行序列化。
- 本地存储: 使用 Datastore 存储用户登录凭证(Cookie)等键值对数据。
- 证据:
build.gradle中引入了retrofit,gson,datastore-preferences等依赖 (app/build.gradle:96-102)。
4. 依赖注入层
使用 Hilt 框架管理应用的所有依赖关系。
- 职责: 自动提供 ViewModel、Repository、NetworkClient 等实例,管理其生命周期。
- 关键模块:
AppModule: 提供 Retrofit、OkHttp 等单例。ViewModelModule: 定义 ViewModel 的注入键。
- 集成: 通过
@HiltAndroidApp注解初始化 Application,@AndroidEntryPoint注解标记 Activity。 - 证据:
build.gradle中应用了dagger.hilt.android.plugin插件 (app/build.gradle:6),并引入了相关依赖库 (app/build.gradle:88-93)。
报告阅读路线图
为了帮助开发者快速理解项目全貌,建议按照以下顺序阅读本技术分析报告:
正在加载图表渲染器...
阅读建议:
- 架构先行: 首先理解 MVI 架构的分层逻辑,这是理解代码组织方式的关键。
- UI 与数据分离: 分别研究 Compose 的 UI 构建方式和 Repository 的数据获取方式,最后再看它们如何在 ViewModel 中结合。
- 关注细节: 在理解整体流程后,深入 Accompanist 库的使用和 Paging 分页逻辑,这些是提升用户体验的关键技术点。
