LibreSudoku 数独应用架构解析:MVVM + Hilt + Room + DataStore + Compose 导航完整技术栈指南
【免费下载链接】Libre-SudokuLibreSudoku - Sudoku app for android built with Kotlin + Jetpack Compose + Material3项目地址: https://gitcode.com/gh_mirrors/li/Libre-Sudoku
🧩 LibreSudoku 是一款基于 Kotlin + Jetpack Compose + Material3 构建的免费开源 Android 数独(Sudoku)应用,支持 6x6 / 9x9 / 12x12 棋盘、多难度级别、游戏统计与自定义导入。本文带你拆解它的现代 Android 技术栈:MVVM 架构、Hilt 依赖注入、Room 数据库、DataStore 偏好存储和 Compose 声明式导航,看看一个生产级数独游戏是如何组织代码的。
📦 技术栈一览:版本目录统一管理
所有第三方库版本集中在 Gradle 版本目录文件 gradle/libs.versions.toml 中声明,这是现代 Android 项目的标准做法。核心组件及其版本如下:
| 组件 | 用途 | 版本 |
|---|---|---|
| Kotlin | 开发语言 | 2.0.21 |
| Jetpack Compose | 声明式 UI | 1.7.5 |
| Material3 | 设计系统 | 1.3.1 |
| Hilt | 依赖注入(DI) | 2.52 |
| Room | 本地数据库 | 2.6.1 |
| DataStore Preferences | 轻量键值存储 | 1.1.1 |
| Compose Destinations | 类型安全导航 | 1.11.6 |
💡 用版本目录(Version Catalog)统一管理依赖,升级只需改一处,避免版本漂移。
🏗️ 分层架构:四层目录各司其职
主代码位于app/src/main/java/com/kaajjo/libresudoku/,按职责分成清晰的四层:
├── core/ 数独核心引擎:生成器、求解器、解析器 ├── data/ 数据层:Room 数据库 + DataStore + 备份 ├── domain/ 领域层:Repository 接口 + UseCase ├── ui/ 表现层:Compose 屏幕 + ViewModel └── di/ Hilt 依赖注入模块这种分层让「玩数独的逻辑」与「存数据、画界面」彻底解耦:
- core 层:app/src/main/java/com/kaajjo/libresudoku/core/qqwing/QQWing.kt 封装了数独生成与求解引擎,还有针对 Gsudoku、OpenSudoku 等格式的 文件导入解析器。
- domain 层:定义 Repository 抽象接口(如 BoardRepository.kt)和细粒度 UseCase(如 GetBoardUseCase.kt),业务规则集中于此,便于单元测试。
🖥️ MVVM:每个屏幕一个 ViewModel
表现层遵循严格的 MVVM 模式:每个功能目录(ui/game/、ui/home/、ui/folders/等)都包含一对文件——XxxScreen.kt(Compose 界面)+XxxViewModel.kt(状态容器)。
以游戏主界面为例,GameViewModel.kt 用MutableStateFlow暴露可观察的游戏状态:
private var _advancedHintMode = MutableStateFlow(false) val advancedHintMode = _advancedHintMode.asStateFlow()界面通过collectAsStateWithLifecycle()订阅这些流,状态变化自动触发 Compose 重组。好处很直观:界面是状态的函数,倒计时、高亮、提示等游戏状态与 UI 代码完全分离,旋转屏幕、进程重建后状态也能恢复。
🧬 Hilt 依赖注入:一个 AppModule 打通数据层
整个应用的依赖图在 AppModule.kt 中装配,这是阅读该项目最快的入口。它做了三件事:
- 提供 Room 数据库单例:
@Provides @Singleton返回 AppDatabase 实例; - DAO → Repository 的接口绑定:把
FolderDao等实现绑定到domain层的FolderRepository接口,上层只依赖抽象; - 提供 DataStore 管理器:注入
AppSettingsManager和ThemeSettingsManager两个@Singleton对象。
启用方式极简:Application 类 LibreSudokuApp.kt 标注@HiltAndroidApp,入口 MainActivity.kt 标注@AndroidEntryPoint,每个 ViewModel 标注@HiltViewModel即可通过构造函数自动注入——零样板代码的依赖图。
🗄️ Room 数据库:自动迁移省心
AppDataBase.kt 定义了 4 个实体和 5 个 DAO:
| 实体 | 对应数据 |
|---|---|
SudokuBoard | 数独棋盘(用户创建/导入的谜题) |
Folder | 棋盘分组文件夹 |
SavedGame | 未完成的游戏存档 |
Record | 对局记录与统计数据 |
两个值得学习的细节:
- AutoMigration:数据库已迭代到 version 6,全部使用
AutoMigration(from = 1, to = 2)等自动迁移,无需手写Migration脚本,schema 变更记录保留在app/schemas/目录可追溯; - TypeConverters:通过 ZonedDateTimeConverter.kt 等转换器,把
ZonedDateTime、Duration、枚举等 Kotlin 类型映射为 SQLite 基础类型,DAO 层直接操作强类型对象。
⚙️ DataStore:配置类数据的最佳归宿
游戏设置、主题偏好这类「键值对」数据不适合进数据库。AppSettingsManager.kt 基于preferencesDataStore(name = "settings")封装,用类型化 Key 管理几十个开关:
private val firstLaunchKey = booleanPreferencesKey("first_launch") private val inputMethodKey = intPreferencesKey("input_method")同目录下还有 ThemeSettingsManager.kt(动态取色、暗色主题、棋盘配色)与 TipCardsDataStore.kt(教程卡片状态)。DataStore 相比传统 SharedPreferences 的优势:基于协程、线程安全、不会崩溃于未初始化的读写。
🧭 Compose 导航:Compose Destinations 类型安全跳转
项目没有手拼字符串路由,而是采用Compose Destinations库(KSP 代码生成):
- 每个可跳转的屏幕 Composable 标注
@Destination,并指定项目自定义的 AnimatedNavigation 转场动画; - 首次启动流程:MainActivity.kt 中检测
firstLaunch状态,自动导航到欢迎页并清空首页回栈; - 路由入口:
DestinationsNavHost(navGraph = NavGraphs.root, ...)挂载在Scaffold底部导航栏之上,根据当前路由自动显隐 NavigationBarComponent。
编译器会生成WelcomeScreenDestination.route等强类型路由对象——写错页面名直接编译报错,彻底告别 "No destination with route xxx" 运行时崩溃。
📋 总结:一张图看懂数据流
用户操作 → Screen(Compose) → ViewModel(StateFlow) ← 重组 ← ↓ UseCase Repository(接口) ↓ Hilt 注入实现 Room(对局/存档) / DataStore(设置)LibreSudoku 的架构亮点在于克制的工程化:不追求多模块拆分,而是在单模块内用清晰的分层目录 + 接口隔离 + 代码生成导航,兼顾了可读性与可维护性。如果你想给自己的 Android 项目引入 MVVM + Hilt + Room 组合拳,这套数独应用源码是非常好的参考样本。🎯
【免费下载链接】Libre-SudokuLibreSudoku - Sudoku app for android built with Kotlin + Jetpack Compose + Material3项目地址: https://gitcode.com/gh_mirrors/li/Libre-Sudoku
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考