手把手教你用 Jetpack Compose 打造一款 Android 提醒应用附源码开源地址https://github.com/cwh1234/remember_app如果觉得有帮助欢迎 ⭐ Star 支持一下 前言生活中总有太多需要记住的事情——亲友的生日、重要的纪念日、证件到期时间、每月账单缴费……稍不留神就容易错过。市面上的提醒类 App 要么广告太多要么功能繁杂不够纯粹。于是我决定自己动手用Jetpack Compose MVVM架构打造一款简洁实用的 Android 提醒应用——Remember App。本文将完整分享这个项目从架构设计到核心实现的全过程适合正在学习 Jetpack Compose 或想了解 Android 现代开发实践的同学参考。✨ 功能概览功能说明生日提醒支持每年重复不再错过亲友生日纪念日纪念重要的日子每年自动提醒✈️出差准备提前通知做好出差准备证件到期身份证、护照等证件到期提醒账单缴费水电网费、贷款等账单提醒自定义灵活创建个性化提醒⏰提前提醒支持设置提前 0-30 天通知每年重复生日、纪念日等支持每年自动重复节假日管理内置中国法定节假日可自定义添加深色模式自动跟随系统深色/浅色主题 技术栈Kotlin Jetpack Compose (Material 3) ├── Room Database → 本地数据持久化 ├── Navigation Compose → 页面导航 ├── ViewModel StateFlow → MVVM 架构 ├── DataStore → 偏好设置存储 ├── KSP → Room 编译期注解处理 └── Coroutines → 异步任务管理版本选型Kotlin 1.8.22Compose BOM 2023.06.00Room 2.5.2Navigation Compose 2.6.0compileSdk / targetSdk 33 项目架构整体采用 Android 官方推荐的MVVM Repository架构遵循单向数据流原则┌─────────────────────────────────────────────┐ │ UI Layer │ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │ │ Reminder │ │ Add │ │ Mine │ │ │ │ Screen │ │ Screen │ │ Screen │ │ │ └────┬─────┘ └────┬─────┘ └────┬─────┘ │ │ │ │ │ │ │ ┌────┴──────────────┴──────────────┴────┐ │ │ │ ViewModels (StateFlow) │ │ │ └────────────────┬──────────────────────┘ │ ├───────────────────┼─────────────────────────┤ │ Data Layer │ │ ┌────────────────┴──────────────────────┐ │ │ │ Repository │ │ │ └────────┬──────────────────┬───────────┘ │ │ │ │ │ │ ┌────────┴──────┐ ┌───────┴──────────┐ │ │ │ ReminderDao │ │ HolidayDao │ │ │ └───────┬───────┘ └───────┬──────────┘ │ │ │ │ │ │ ┌───────┴──────────────────┴──────────┐ │ │ │ Room Database │ │ │ └──────────────────────────────────────┘ │ └─────────────────────────────────────────────┘项目目录结构app/src/main/java/com/remember/app/ ├── RememberApp.kt # Application初始化数据库和仓库 ├── MainActivity.kt # 唯一 Activity入口 ├── model/ │ └── ReminderType.kt # 提醒类型枚举 ├── data/ │ ├── database/ │ │ ├── AppDatabase.kt # Room 数据库定义 预填充 │ │ ├── dao/ │ │ │ ├── ReminderDao.kt # 提醒数据访问 │ │ │ └── HolidayDao.kt # 节假日数据访问 │ │ └── entity/ │ │ ├── Reminder.kt # 提醒实体 │ │ └── Holiday.kt # 节假日实体 │ └── repository/ │ ├── ReminderRepository.kt │ └── HolidayRepository.kt ├── navigation/ │ └── AppNavigation.kt # 底部导航 页面路由 └── ui/ ├── theme/ # Material 3 主题配置 ├── add/ # 添加提醒页面 ViewModel ├── reminder/ # 提醒列表页面 ViewModel └── mine/ # 我的页面 ViewModel 核心代码详解1. 数据实体设计提醒实体Reminder是整个应用的核心Entity(tableNamereminders)dataclassReminder(PrimaryKey(autoGeneratetrue)valid:Long0,valtitle:String,// 提醒标题valtype:String,// 提醒类型枚举名valtargetDate:Long,// 目标日期时间戳valadvanceDays:Int3,// 提前提醒天数0-30valnotes:String,// 备注valisActive:Booleantrue,// 是否启用valisRepeatYearly:Booleanfalse,// 是否每年重复valcreatedAt:LongSystem.currentTimeMillis())设计要点targetDate使用Long时间戳存储方便做日期比较和排序advanceDays控制提前多少天开始提醒支持 0-30 天滑块调节isRepeatYearly标记生日、纪念日等每年重复的事项isActive支持软删除用户可随时暂停/恢复提醒2. Room DAO — Flow 响应式数据Room 与 Kotlin Flow 的结合是本文亮点之一DaointerfaceReminderDao{// 获取从今天起的所有活跃提醒按日期升序Query(SELECT * FROM reminders WHERE is_active 1 AND target_date :today ORDER BY target_date ASC)fungetUpcomingReminders(today:Long):FlowListReminder// 获取所有活跃提醒Query(SELECT * FROM reminders WHERE is_active 1 ORDER BY target_date ASC)fungetAllActiveReminders():FlowListReminder// 插入提醒Insert(onConflictOnConflictStrategy.REPLACE)suspendfuninsert(reminder:Reminder):Long// 切换启用状态Query(UPDATE reminders SET is_active :isActive WHERE id :id)suspendfunsetActive(id:Long,isActive:Boolean)}为什么要用Flow— DAO 返回FlowListReminder数据变化时 UI 自动更新无需手动刷新。这就是响应式编程Reactive Programming的核心优势。3. ViewModel — 状态管理核心以AddViewModel为例展示标准的 MVVM 状态管理dataclassAddUiState(valselectedType:ReminderTypeReminderType.BIRTHDAY,valtitle:String,valtargetDate:LongSystem.currentTimeMillis(),valadvanceDays:Int3,valnotes:String,valisRepeatYearly:Booleanfalse,valisSaving:Booleanfalse,valsaveSuccess:Booleanfalse,valerrorMessage:String?null)classAddViewModel(application:Application):AndroidViewModel(application){privateval_uiStateMutableStateFlow(AddUiState())valuiState:StateFlowAddUiState_uiState.asStateFlow()funupdateAdvanceDays(days:Int){_uiState.value_uiState.value.copy(advanceDaysdays.coerceIn(0,90))}funsaveReminder(){valstate_uiState.valueif(state.title.isBlank()){_uiState.valuestate.copy(errorMessage请输入提醒标题)return}viewModelScope.launch{_uiState.value_uiState.value.copy(isSavingtrue)valreminderReminder(titlestate.title.trim(),typestate.selectedType.name,targetDatestate.targetDate,advanceDaysstate.advanceDays,notesstate.notes.trim(),isRepeatYearlystate.isRepeatYearly)reminderRepository.insert(reminder)_uiState.valueAddUiState(saveSuccesstrue)// 保存成功重置表单}}}核心思路使用data class封装所有 UI 状态单一数据源Single Source of TruthMutableStateFlowasStateFlow()保证外部只读内部可写data class.copy()实现不可变状态更新所有异步操作通过viewModelScope.launch管理避免内存泄漏4. 提醒列表 — 智能分组显示ReminderViewModel将提醒分为**“最近提醒和接下来”**两组privatefunloadReminders(){valtodaygetTodayStart()valdayInMillis86_400_000LvaltodayDaystoday/dayInMillis viewModelScope.launch(Dispatchers.IO){reminderRepository.getUpcomingReminders(today).map{allUpcoming-// 在 Kotlin 层分离即将到来和最近提醒已进入窗口期valdueallUpcoming.filter{r-valtargetDaysr.targetDate/dayInMillis(targetDays-r.advanceDays)todayDays}ReminderUiState(upcomingRemindersallUpcoming,dueRemindersdue,isLoadingfalse)}.catch{e-/* 错误处理 */}.collect{state-_uiState.valuestate}}}分组逻辑如果目标日期 - 提前天数 ≤ 今天则该提醒进入最近提醒组即已进入提醒窗口期其余放入接下来组。每个提醒卡片显示剩余天数进入窗口期的显示高亮色一目了然。5. 底部导航 — Material 3 NavigationBar使用 Material 3 的NavigationBar实现三 Tab 底部导航ComposablefunAppNavigation(){valnavItemslistOf(BottomNavItem.Reminder,// 提醒列表BottomNavItem.Add,// 添加提醒BottomNavItem.Mine// 个人中心)varselectedIndexbyremember{mutableStateOf(0)}Scaffold(bottomBar{NavigationBar(tonalElevation8.dp){navItems.forEachIndexed{index,item-NavigationBarItem(selectedselectedIndexindex,onClick{selectedIndexindex},icon{Icon(/* selected/unselected icon */)},label{Text(item.title)},colorsNavigationBarItemDefaults.colors(/* 自定义颜色 */))}}}){innerPadding-when(selectedIndex){0-ReminderScreen()1-AddScreen()2-MineScreen()}}}设计思路采用简单的selectedIndex状态切换而非 Navigation Compose 的路由机制适合这种同级页面切换场景代码更简洁无需传递路由参数。6. Material 3 主题 — 支持深色模式privatevalLightColorSchemelightColorScheme(primaryPrimary,// 温暖的橙色 #FF6B35backgroundBackground,// #FAFAFAsurfaceSurface,// White// ...)ComposablefunRememberAppTheme(darkTheme:BooleanisSystemInDarkTheme(),content:Composable()-Unit){valcolorSchemeif(darkTheme)DarkColorSchemeelseLightColorScheme// 动态设置状态栏颜色valviewLocalView.current SideEffect{valwindow(view.contextasActivity).window window.statusBarColorcolorScheme.primary.toArgb()}MaterialTheme(colorSchemecolorScheme,typographyAppTypography,contentcontent)}主题特点主色调采用温暖橙色#FF6B35给人温馨、积极的感受每种提醒类型有独立配色生日粉色、出差蓝色、账单绿色等完美适配系统深色模式自动切换状态栏颜色跟随主题主色7. 添加提醒界面 — 分类卡片 表单添加页面采用3 列网格卡片选择提醒类型 表单区域填写详情// 6 种提醒类型的分类网格LazyVerticalGrid(columnsGridCells.Fixed(3)){items(reminderCategories){category-CategoryCard(categorycategory,isSelecteduiState.selectedTypecategory.type,onClick{viewModel.updateType(category.type)})}}每个分类卡片有独立图标emoji、名称、颜色选中时显示高亮边框和阴影交互反馈清晰。8. 数据库预填充 — 内置节假日应用首次启动时通过 Room 的Callback.onCreate()预填充中国法定节假日overridefunonCreate(db:SupportSQLiteDatabase){super.onCreate(db)valholidayslistOf(元旦tocreateDate(currentYear,0,1),春节tocreateDate(currentYear,1,10),清明节tocreateDate(currentYear,3,5),劳动节tocreateDate(currentYear,4,1),端午节tocreateDate(currentYear,5,10),中秋节tocreateDate(currentYear,8,15),国庆节tocreateDate(currentYear,9,1),除夕tocreateDate(currentYear,11,30))for((name,date)inholidays){db.execSQL(INSERT OR IGNORE INTO holidays (name, date, is_enabled, is_default) VALUES (?, ?, 1, 1),arrayOf(name,date))}}用户可以在我的页面随时开启/关闭任意节假日也可以添加自定义节假日。9. 全局异常保护在RememberApp中设置了全局异常处理器防止未预期错误导致闪退Thread.setDefaultUncaughtExceptionHandler{thread,throwable-Log.e(RememberApp,!!! UNCAUGHT EXCEPTION !!!,throwable)// 数据库损坏时尝试自动恢复if(throwable.message?.contains(database)true||throwable.message?.contains(Room)true){deleteDatabase(remember_app_db)}defaultHandler?.uncaughtException(thread,throwable)} 构建与运行环境要求工具版本Android StudioFlamingo (2022.2.1) 或更高JDK11Android SDK33Gradle7.4.2快速开始# 1. 克隆项目gitclone https://github.com/cwh1234/remember_app.gitcdremember_app# 2. 构建 Debug APK./gradlew assembleDebug# 3. 安装到设备./gradlew installDebug或者直接用 Android Studio 打开项目点击 Run 按钮运行。 项目亮点总结纯 Jetpack Compose— 全部 UI 使用声明式 Compose 编写0 XML 布局文件除了 manifest 和资源文件标准 MVVM 架构— ViewModel StateFlow Repository 模式单向数据流职责清晰响应式数据— Room DAO 返回 Flow数据变化自动触发 UI 刷新Material 3 设计— 紧跟 Google 最新设计规范支持 Dynamic Color完善的异常处理— try-catch 覆盖所有关键路径全局崩溃保护代码精简— 核心代码约 20 个 Kotlin 文件小而美适合学习参考即装即用— 提供预构建 APK无需编译即可体验 后续规划通知栏推送WorkManager Notification桌面小组件App Widget云端同步Firebase / 自建后端农历日期支持数据导出/导入更多自定义主题色 关于开源本项目采用MIT License开源你可以自由地✅ 学习参考✅ 二次开发✅ 商业使用GitHub 仓库https://github.com/cwh1234/remember_app如果这个项目对你有帮助欢迎给个 ⭐ Star你的支持是我持续更新的动力 写在最后这个项目从零到一完整实践了 Jetpack Compose MVVM 的现代 Android 开发流程。如果你是 Android 初学者希望这篇文章能帮你建立对 Compose 开发的基本认知如果你是老手也欢迎提出改进建议互相学习。如果你在运行过程中遇到任何问题欢迎在 GitHub 提 Issue我会尽快回复。