news 2026/9/4 9:28:17

Android毕业设计实战:老年人服药提醒App开发全流程解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Android毕业设计实战:老年人服药提醒App开发全流程解析

简介:这是一套面向计算机专业本科生的Android毕业设计实战资源,聚焦老年人健康管理场景,实现服药提醒核心功能,适用于课程设计、期末大作业及毕设选题。项目采用前后端分离架构,后端基于SpringBoot开发,前端为Android原生应用,数据库使用MySQL,配套完整注释与部署教程,新手可快速上手。压缩包共6个文件,包含3个核心ZIP(含Android源码、SpringBoot后台代码、演示视频)、2份TXT说明文档(含使用指南与部署指引)及1个SQL数据库脚本,总大小92.18MB,结构清晰、模块分明,便于分阶段学习与调试。已有334人下载学习,资源提供从环境搭建、接口联调到真机测试的全流程支持,涵盖数据库建表语句、Gradle/Maven配置要点、关键业务逻辑注释及常见运行问题解决方案,切实降低开发门槛,提升项目交付质量。

1. 项目缘起与核心价值:为什么选择“老年人服药提醒”作为毕业设计?

做毕业设计,最头疼的往往不是技术实现,而是选题。选一个“烂大街”的课题,比如图书管理系统、学生信息管理系统,虽然能完成,但缺乏新意,在答辩时也很难给老师留下深刻印象。选一个过于前沿或复杂的课题,又容易因为时间、精力或技术储备不足而“烂尾”。我当年做毕业设计时,也在这个问题上纠结了很久。最终,我选择了“基于Android的老年人服药提醒App”这个方向,现在看来,这是一个非常明智的决定。它不仅让我顺利通过了答辩,获得了不错的成绩,更重要的是,这个项目具备很强的现实意义和技术综合性,能充分展示一个准Android开发者的综合能力。

为什么说它是个好选题?首先,它切中了一个真实的社会痛点。随着人口老龄化加剧,许多独居或记忆力减退的老年人,常常会忘记按时服药,或者记不清是否已经服过药,这直接关系到他们的健康与安全。一个简单、易用、可靠的服药提醒工具,市场需求是真实存在的。其次,从技术层面看,这个项目麻雀虽小,五脏俱全。它几乎涵盖了Android应用开发的核心知识点:UI界面设计(特别是针对老年人的大字体、高对比度设计)、后台服务与定时任务(实现精准提醒)、本地数据库存储(管理药品和服药记录)、以及可能涉及的通知系统、多媒体(声音、震动)等。对于数据库课程设计,你也能在这里找到用武之地,设计一个合理、高效的本地数据库Schema来支撑整个App的数据流转。

所以,如果你正在为Android毕业设计选题发愁,或者想找一个能串联起多门课程知识的实战项目,“老年人服药提醒App”绝对是一个值得深入挖掘的金矿。接下来,我将以我自己的实现为例,手把手带你从零开始,完成这个既有温度又有技术深度的项目。我会重点讲解设计思路、关键技术的实现细节,以及我在开发过程中踩过的那些“坑”,并提供完整的源码和数据库设计供你参考。

2. 需求分析与功能设计:从用户场景出发,构建产品骨架

在动手写代码之前,我们必须先想清楚:这个App到底要给谁用?他们要解决什么问题?只有把需求理清,后续的设计和开发才不会跑偏。

2.1 核心用户画像与使用场景

我们的核心用户是老年人,以及可能协助他们管理药物的子女或护工。因此,设计必须遵循“为老年人设计”的原则:

  • 视觉上:字体要大,图标要清晰,色彩对比度要高,避免使用复杂的渐变或扁平化设计中不易辨识的细节。
  • 交互上:操作流程要极简,步骤要少,点击区域要大,避免需要精确长按、双指缩放等复杂手势。
  • 认知上:语言要通俗直白,避免专业术语。功能逻辑要一目了然,不需要用户去“探索”或“学习”。

一个典型的使用场景是:张大爷患有高血压和糖尿病,每天需要早晚各服一次降压药,中午饭后服一次降糖药。他视力不好,手指也不太灵活。我们的App需要帮他:

  1. 轻松添加这三种药,并设置好每天服用的具体时间(如08:00, 20:00, 13:00)。
  2. 到了时间,App能以足够响亮且持续的铃声(考虑老年人可能耳背)和手机震动进行提醒。
  3. 提醒界面要极其简单,最好全屏显示,只提供“已服用”和“跳过”两个大按钮。张大爷一眼就能看懂,点一下“已服用”即可。
  4. 记录张大爷每次的服药动作,方便子女远程查看(通过本地记录或简单的数据导出),了解父亲的服药依从性。

2.2 功能模块拆解

基于以上场景,我们可以将App的功能拆解为以下几个核心模块:

  1. 药品管理模块

    • 添加药品:输入药品名称、规格、用法用量(如“一次一片”、“一次一包”)、备注(如“餐后服用”)。
    • 设置服药计划:这是核心。需要为每种药设置提醒周期(每天、每周特定几天、隔天等)和一天内的具体提醒时间点(可多个)。
    • 查看与编辑药品:以列表形式展示所有药品,支持修改和删除。
  2. 提醒与通知模块

    • 定时任务调度:根据药品的提醒计划,在指定时间触发提醒。这里必须考虑Android系统的后台限制(尤其是Android 8.0以上的版本)。
    • 前台服务与通知:为了确保提醒不被系统“杀死”,需要启动一个前台服务,并创建一个常驻的通知栏通知,告诉用户“服药提醒服务正在运行”。
    • 全屏提醒界面:当提醒触发时,启动一个全屏的Activity或使用高优先级的通知,播放铃声和震动,确保即使用户不在使用手机也能注意到。
  3. 服药记录与日志模块

    • 记录操作:用户点击“已服用”或“跳过”时,记录本次操作的时间、药品、执行动作。
    • 历史查看:以日历或列表形式,展示历史服药记录,清晰标记“已服”、“跳过”、“未处理”。
    • 数据统计(进阶功能):生成简单的依从性报告,如本周按时服药率。
  4. 本地数据库模块

    • 数据持久化:所有药品信息、服药计划、历史记录都需要安全地存储在本地。
    • 数据结构设计:需要设计合理的表结构来关联药品、计划、记录。
  5. 设置与辅助功能模块

    • 提醒音设置:允许用户选择或自定义提醒铃声。
    • 震动设置:开关震动。
    • 字体大小调整:提供一档“超大字体”模式开关。
    • 数据备份/导出:将记录导出为文件,方便分享给子女或医生。

明确了功能,我们就有了清晰的开发路线图。接下来,我们进入技术选型与核心实现的环节。

3. 技术选型与核心实现:如何构建一个稳定可靠的后台提醒系统?

这是整个项目的技术核心,也是毕业设计答辩时老师最可能深挖的部分。你需要清晰地阐述为什么选择这些技术,以及它们是如何协同工作的。

3.1 数据库设计:SQLite与Room的优雅结合

本地存储我们选择SQLite,这是Android的原生支持,轻量且无需网络。但直接使用SQLiteOpenHelper会写很多样板代码,因此我强烈推荐使用Google Jetpack组件中的Room持久化库。它是在SQLite之上的一层抽象,提供了编译时SQL检查、方便的ORM(对象关系映射)支持,能极大提升开发效率和代码安全性。

我们的数据库至少需要三张核心表:

  • 药品表 (Medicine):存储药品静态信息。

    CREATE TABLE medicine ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, -- 药品名 dosage TEXT, -- 单次用量,如“1片” note TEXT -- 备注,如“餐后服用” );
  • 服药计划表 (Schedule):存储每种药的提醒规则。这里的设计是关键,它决定了提醒的灵活性。

    CREATE TABLE schedule ( id INTEGER PRIMARY KEY AUTOINCREMENT, medicine_id INTEGER NOT NULL, -- 外键,关联药品 enabled INTEGER DEFAULT 1, -- 是否启用该计划 repeat_mode TEXT NOT NULL, -- 重复模式,如 'daily', 'weekly:1,3,5' (表示每周一、三、五) time TEXT NOT NULL, -- 提醒时间,格式如 '08:00', 如果一天多次,可存为 '08:00,13:00,20:00'或用另一张表关联 FOREIGN KEY (medicine_id) REFERENCES medicine(id) ON DELETE CASCADE );

    注意:关于一天多次提醒的存储,有两种常见方案。一是将多个时间点用逗号拼接存在一个字段(如上例),解析稍麻烦但简单;二是单独建一张“计划时间点”表,与Schedule表是一对多关系,更符合数据库范式。对于毕业设计,我建议用第二种,更能体现你对数据库关系的理解。

  • 服药记录表 (Record):记录每次提醒的用户反馈。

    CREATE TABLE record ( id INTEGER PRIMARY KEY AUTOINCREMENT, schedule_id INTEGER NOT NULL, -- 关联到具体的计划(和时间点) medicine_id INTEGER NOT NULL, -- 冗余存储,方便查询 scheduled_time INTEGER NOT NULL, -- 计划服药时间(时间戳) action_time INTEGER, -- 用户操作时间(时间戳),NULL表示未处理 action TEXT, -- 'TAKEN'(已服用), 'SKIPPED'(跳过), 'MISSED'(系统标记为错过) FOREIGN KEY (schedule_id) REFERENCES schedule(id), FOREIGN KEY (medicine_id) REFERENCES medicine(id) );

使用Room,你需要定义对应的Entity(实体类)、Dao(数据访问对象)和Database类。这部分代码结构清晰,网上教程也很多,关键是理解表之间的关系。

3.2 定时提醒:AlarmManager与WorkManager的抉择与实战

如何在准确的时间触发提醒?这是Android后台任务的老大难问题。主要候选方案有AlarmManagerWorkManagerJobScheduler

  • AlarmManager:最传统、最“强硬”的定时器。它可以设置精确的闹钟,即使在设备休眠时也能唤醒CPU执行操作。这对于服药提醒这种对时间准确性要求高的场景是必须的。但是,从Android 6.0 (API 23) 开始,尤其是Android 8.0 (API 26) 引入了“后台执行限制”后,AlarmManagersetExact方法行为发生了变化,在低电量和Doze模式下可能不精确。
  • WorkManager:Google推荐的后台任务调度库,它兼容性好,能根据系统版本自动选择最佳实现(JobScheduler, AlarmManager+GcmNetworkManager等)。但它设计用于延迟容忍度较高的周期性任务(如每天同步一次数据),对于“每天08:00准时响铃”这种需求,其时间准确性无法保证。
  • JobScheduler:API 21以上系统原生支持,功能强大,但需要自己处理版本兼容。

我的方案是:两者结合,以AlarmManager为主,WorkManager为辅。

  1. 核心精准提醒使用AlarmManager:为每一个未来的、独立的服药时间点(例如,明天08:00)设置一个精确的AlarmManager闹钟(使用setExactAndAllowWhileIdlesetAlarmClock,后者会在状态栏显示一个即将到来的闹钟图标,用户体验更好)。当闹钟触发时,启动一个前台服务,并弹出全屏提醒界面。

    // 示例:设置一个精确的闹钟 val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager val intent = Intent(context, ReminderReceiver::class.java).apply { putExtra("schedule_id", scheduleId) putExtra("medicine_name", medicineName) } val pendingIntent = PendingIntent.getBroadcast(context, requestCode, intent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE) // 使用 setAlarmClock, 用户体验好,在Doze模式下也能相对准时触发 val triggerTime = ... // 计算出的下一次提醒的时间戳 val showIntent = Intent(context, MainActivity::class.java) // 点击闹钟图标跳转的Intent val showPendingIntent = PendingIntent.getActivity(context, 0, showIntent, PendingIntent.FLAG_IMMUTABLE) val alarmClockInfo = AlarmManager.AlarmClockInfo(triggerTime, showPendingIntent) alarmManager.setAlarmClock(alarmClockInfo, pendingIntent)

    踩坑记录PendingIntentFLAG_IMMUTABLE标志在Android 12 (API 31) 及以上是必须的,否则会崩溃。同时,要管理好requestCode,确保每个独立的提醒都有唯一的requestCode,这样才能单独取消。

  2. 使用WorkManager进行“兜底”和计划重置:由于用户可能重启手机、强制停止App,或者系统为了省电清除了Alarm。我们可以注册一个监听设备重启的广播接收器,在重启后使用WorkManager安排一个一次性的、立即执行的任务,这个任务的工作就是重新从数据库读取所有已启用的服药计划,并为每个计划的未来时间点重新设置AlarmManager闹钟。同时,可以安排一个每天一次的周期性Work,在深夜(如凌晨2点)执行,检查并设置第二天的所有提醒,作为二次保障。

    // 在Application或启动Activity中初始化计划 class MyApplication : Application() { override fun onCreate() { super.onCreate() // 检查并重置所有闹钟 ReminderScheduler.rescheduleAllReminders(this) // 安排一个每日的兜底检查任务 val dailyCheckRequest = PeriodicWorkRequestBuilder<DailyReminderCheckWorker>(1, TimeUnit.DAYS) .setInitialDelay(1, TimeUnit.HOURS) // 1小时后首次执行 .build() WorkManager.getInstance(this).enqueueUniquePeriodicWork( "daily_reminder_check", ExistingPeriodicWorkPolicy.KEEP, dailyCheckRequest ) } }

3.3 前台服务与全屏提醒:确保提醒能被用户感知

当AlarmManager触发的广播接收器ReminderReceiver被调用时,我们不能在里面直接进行长时间操作或启动界面。标准做法是:

  1. 启动一个前台服务:在ReminderReceiveronReceive中,启动一个IntentService或JobIntentService(兼容性好),并在这个Service里启动前台服务。

    class ReminderService : JobIntentService() { override fun onHandleWork(intent: Intent) { // 1. 创建通知渠道(Android 8.0+必需) // 2. 构建一个常驻通知,启动前台服务 startForeground(NOTIFICATION_ID, buildPersistentNotification()) // 3. 启动全屏提醒Activity val fullScreenIntent = Intent(this, ReminderActivity::class.java).apply { putExtras(intent.extras!!) flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP } startActivity(fullScreenIntent) } }

    这个前台服务的通知会一直显示在状态栏,告诉用户“服药提醒服务正在运行”,降低被系统杀死的概率。

  2. 设计全屏提醒Activity:这个Activity的布局要极其简单。背景可以用醒目的颜色(如浅红色),中央大字体显示“该服用[药品名]了!”和用法用量,下方放置两个巨大的按钮:“✅ 已服用”和“⏭ 跳过”。同时,在onCreate中播放铃声和启动震动。

    class ReminderActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // 点亮屏幕并解锁(需要权限) window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON or WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD or WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED or WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON) setContentView(R.layout.activity_reminder_fullscreen) // 播放提醒音 val ringtone = RingtoneManager.getRingtone(this, Settings.System.DEFAULT_ALARM_ALERT_URI) ringtone.play() // 震动 val vibrator = getSystemService(Context.VIBRATOR_SERVICE) as Vibrator val pattern = longArrayOf(0, 1000, 1000) // 等待0ms,震动1000ms,停止1000ms,循环 vibrator.vibrate(VibrationEffect.createWaveform(pattern, 0)) // 0表示不重复 // 按钮点击事件 buttonTaken.setOnClickListener { // 1. 停止铃声和震动 ringtone.stop() vibrator.cancel() // 2. 在数据库中插入一条“TAKEN”记录 // 3. 取消本次提醒对应的Alarm(如果是一次性闹钟) // 4. 设置下一个周期的闹钟(如果是周期性任务) // 5. 关闭Activity finish() } // ... 跳过按钮类似 } }

    重要提示:播放铃声和震动需要相应的权限(VIBRATE权限是普通权限,声明即可)。在Android 10及以上,后台启动Activity限制很严,但从前台服务启动全屏Activity通常是允许的,尤其是用于闹钟、提醒这类用户明确期待的场景。

4. 数据库操作的实战细节与优化:Room的高级用法与数据同步

数据库不仅仅是建表存数据,如何高效、安全地操作数据,处理关联查询,是体现工程能力的地方。

4.1 使用Room处理关联查询与数据观察

我们的数据是关联的:查看历史记录时,需要同时显示药品名和计划时间。Room通过@Relation注解或返回自定义的POJO(非Entity类)可以轻松实现。

例如,我们想查询一个包含药品名和记录信息的视图:

// 定义一个非Entity的数据类,用于承载查询结果 data class RecordWithMedicine( @Embedded val record: Record, @Relation(parentColumn = "medicine_id", entityColumn = "id") val medicine: Medicine, @Relation(parentColumn = "schedule_id", entityColumn = "id") val schedule: Schedule ) // 在RecordDao中定义查询方法 @Dao interface RecordDao { @Transaction // 确保关联查询的原子性 @Query("SELECT * FROM record ORDER BY scheduled_time DESC") fun getAllRecordsWithDetails(): LiveData<List<RecordWithMedicine>> }

注意这里返回的是LiveData<List<RecordWithMedicine>>。这是Room与Android Architecture Components结合的精华。LiveData是一个可观察的数据持有者,当数据库中的记录发生变化时,UI层(如Activity、Fragment)会自动收到通知并更新界面。这实现了数据的响应式更新,你无需手动在每次增删改查后去刷新UI列表。

4.2 事务处理与数据一致性

当用户点击“已服用”时,我们需要执行多个操作:插入记录、更新下次提醒时间、可能还要更新药品的剩余数量。这些操作必须作为一个整体,要么全部成功,要么全部失败,否则会出现数据不一致(例如,记录了服药但闹钟没更新)。Room的@Dao接口方法默认就在事务中执行。对于自定义的复杂事务,可以使用@Transaction注解。

@Dao interface MedicineDao { @Transaction suspend fun takeMedicine(record: Record, nextAlarmTime: Long) { // 1. 插入服药记录 insertRecord(record) // 2. 更新Schedule表中的下次提醒时间(如果设计中有此字段) updateScheduleNextAlarm(record.scheduleId, nextAlarmTime) // 3. 可以在这里触发其他逻辑,如更新统计信息 } }

使用Kotlin的suspend函数配合协程,可以方便地在后台线程执行这些数据库操作,避免阻塞主线程。

4.3 数据库迁移与版本管理

在开发过程中,你的数据库结构很可能发生变化。比如最初Schedule表没有enabled字段,后来加上了。如果你直接修改Entity类并运行App,旧用户会遭遇数据库崩溃。Room通过Migration类来处理版本升级。

@Database(entities = [Medicine::class, Schedule::class, Record::class], version = 2) abstract class AppDatabase : RoomDatabase() { companion object { // 定义从版本1到版本2的迁移 private val MIGRATION_1_2 = object : Migration(1, 2) { override fun migrate(database: SupportSQLiteDatabase) { // 给schedule表增加enabled字段,默认值为1(启用) database.execSQL("ALTER TABLE schedule ADD COLUMN enabled INTEGER NOT NULL DEFAULT 1") } } fun buildDatabase(context: Context): AppDatabase { return Room.databaseBuilder( context.applicationContext, AppDatabase::class.java, "medicine_reminder.db" ).addMigrations(MIGRATION_1_2) // 添加迁移 .build() } } }

切记:每次修改Entity(增删改字段、增删改表)或新增Entity,都需要提升@Database注解中的version号,并提供相应的Migration。如果不提供,Room会尝试删除所有表并重建,导致用户数据丢失,这是绝对要避免的。

5. 界面设计与用户体验优化:为老年人量身定做

功能实现了,但如果界面让老年人无从下手,那这个App就是失败的。UI/UX设计在这里和技术实现同等重要。

5.1 布局与视觉设计原则

  • 使用ConstraintLayout:它能够更好地实现复杂界面的响应式布局,确保在不同尺寸和密度的屏幕上都能有良好的显示效果。
  • 字体与尺寸:所有文本的textSize至少使用18sp,重要标题使用24sp或更大。使用sp单位而非dp,这样用户如果在系统设置中调整了字体大小,你的App也会跟随变化。
  • 颜色与对比度:背景与前景文字的对比度至少要满足WCAG AA标准(4.5:1)。避免使用浅灰色文字。按钮使用高饱和度的颜色(如蓝色、绿色),与背景形成鲜明对比。可以提供一个“高对比度”主题开关。
  • 间距与点击区域:按钮要足够大,minHeight至少设为48dp(Android Material Design建议的最小触摸目标尺寸)。元素之间的间距也要拉大,防止误触。

5.2 核心界面实现示例:添加药品页面

这个页面需要平衡信息的完整性和操作的简便性。

<!-- activity_add_medicine.xml 简化示例 --> <ScrollView> <LinearLayout orientation="vertical" padding="16dp"> <TextView text="药品名称" textSize="20sp"/> <EditText id="@+id/etMedicineName" hint="请输入药品名,如:阿司匹林" textSize="18sp" minHeight="48dp"/> <TextView text="用法用量" textSize="20sp"/> <EditText id="@+id/etDosage" hint="如:一次一片,一日三次" textSize="18sp" minHeight="48dp"/> <TextView text="设置提醒" textSize="20sp"/> <!-- 时间选择器,使用大按钮触发 --> <Button id="@+id/btnPickTime" text="选择提醒时间" textSize="18sp" minHeight="56dp"/> <TextView id="@+id/tvSelectedTime" textSize="18sp"/> <!-- 重复周期选择,可以用一组大号CheckBox表示周一至周日 --> <LinearLayout orientation="horizontal"> <CheckBox text="周一" textSize="16sp" scaleX="1.2" scaleY="1.2"/> <!-- ... 周二至周日 --> </LinearLayout> <!-- 保存按钮,做得特别大和醒目 --> <Button id="@+id/btnSave" text="保存药品" textSize="22sp" minHeight="64dp" background="@color/colorPrimary" textColor="@android:color/white"/> </LinearLayout> </ScrollView>

在代码中,时间选择可以使用MaterialTimePicker,日期选择使用MaterialDatePicker,它们都是Material Design组件库的一部分,样式现代且易于使用。

5.3 辅助功能支持

这是很多开发者会忽略,但能极大提升应用包容性的部分。Android提供了完善的辅助功能(Accessibility)支持。

  • 内容描述:为所有ImageButton、ImageView添加android:contentDescription属性,方便屏幕阅读器(如TalkBack)为视障用户描述图片内容。
  • 焦点顺序:通过android:nextFocusDownandroid:nextFocusForward等属性,合理控制使用键盘或方向键导航时的焦点顺序。
  • 测试:在手机上开启TalkBack,尝试不依赖视觉,仅通过语音反馈和手势来操作你的App,你会发现很多可以改进的地方。

6. 项目集成、测试与答辩准备:从代码到成果的最后一公里

完成了核心模块开发,接下来就是整合、测试和准备展示。

6.1 项目结构组织与模块化

一个清晰的项目结构能让你的代码更易维护,也给答辩老师留下好印象。推荐按功能模块分包:

com.yourcompany.medicineReminder/ ├── data/ │ ├── local/ # 数据库相关 │ │ ├── dao/ │ │ ├── entity/ │ │ └── AppDatabase.kt │ └── repository/ # 数据仓库,统一数据源入口 ├── di/ # 依赖注入(如使用Hilt) ├── reminder/ # 提醒相关核心逻辑 │ ├── scheduler/ # AlarmManager调度逻辑 │ ├── service/ # 前台服务 │ └── receiver/ # 广播接收器 ├── ui/ │ ├── addmedicine/ # 添加药品界面 │ ├── main/ # 主界面(药品列表) │ ├── history/ # 历史记录界面 │ └── reminder/ # 全屏提醒界面 ├── utils/ # 工具类 └── App.kt # 自定义Application

使用Repository模式来统一管理数据源(本地数据库、未来可能的网络),让ViewModel不直接接触Dao,降低耦合。

6.2 系统性测试方案

毕业设计不能只演示“Happy Path”。你需要系统地测试,并能在答辩时阐述你的测试方法。

  1. 功能测试
    • 添加、编辑、删除药品。
    • 设置复杂的服药计划(如每周一、三、五的早8点和晚8点)。
    • 等待或修改系统时间触发提醒,验证全屏界面、铃声、震动是否正常。
    • 点击“已服用”/“跳过”,检查记录是否生成,对应的未来闹钟是否被正确更新或取消。
  2. 边界与异常测试
    • 时间边界:设置跨午夜的提醒(如23:50),检查日期处理是否正确。
    • 系统交互:触发提醒时,按下音量键、电源键,App行为如何?(应不影响提醒,全屏Activity应保持在最前)。
    • 后台限制:强制停止App后,重启手机,检查WorkManager的兜底任务是否能重新设置闹钟。
    • 低电量模式/省电模式:开启后,测试AlarmManager.setAlarmClock()是否依然相对准时。
    • 数据库异常:尝试插入空药品名,看是否有校验提示。
  3. 用户体验测试
    • 将系统字体调到最大,查看界面是否错乱。
    • 开启TalkBack,测试核心流程是否可访问。

6.3 毕业设计文档与答辩要点

一份优秀的毕业设计,除了代码,还需要清晰的文档。

  • 论文/设计说明书:结构应包括绪论(背景与意义)、需求分析、系统设计(总体设计、数据库设计、模块设计)、系统实现(关键代码与界面截图)、系统测试、总结与展望。切忌代码堆砌,重点用流程图、时序图、类图、表结构图来阐述设计,用核心代码片段说明实现。
  • 答辩PPT:提炼精华。首页:题目、姓名、学号。接着快速讲背景和意义(1页)。重点讲系统设计(2-3页):展示你的系统架构图、数据库ER图、核心模块关系图。然后讲关键技术与实现难点(3-4页):这是展示你技术深度的部分,详细讲AlarmManager与WorkManager的选型与结合、Room数据库的关联查询与LiveData、前台服务保活策略。接着是功能演示(准备录屏或现场操作),最后是总结与致谢
  • 答辩陈述:练习用技术语言清晰地表达。老师可能会问:
    • “你的提醒机制如何保证在Android高版本上的可靠性?”(考察后台限制的应对)
    • “如果一种药需要一天吃三次,你的数据库是怎么设计的?”(考察数据库设计能力)
    • “用户反馈说有时没提醒,你的排查思路是什么?”(考察问题解决能力)
    • “有没有考虑过加入云端同步功能?如果加,架构要怎么调整?”(考察扩展性思维)

准备好这些问题的答案,你的答辩就会非常从容。

这个项目做下来,你会对Android开发的生命周期、后台任务、数据库、UI设计有一个全面而深入的理解。它不仅仅是一个毕业设计的“作业”,更是一个可以真正运行、解决实际问题的作品。希望这份超详细的指南能为你扫清障碍,祝你开发顺利,答辩成功!

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/4 9:27:57

【数据治理实践】第 2 期:顶层设计之数据战略

前言&#xff1a;无战略&#xff0c;不治理在第 1 期《数据治理认知与体系框架》中&#xff0c;我们建立了数据治理的基础认知&#xff0c;掌握了 DMBOK 与 DCMM 主流框架。然而&#xff0c;有了框架并不意味着治理能够成功落地。许多企业面临的困境是&#xff1a;治理动作与业…

作者头像 李华
网站建设 2026/9/4 9:26:04

腾龙70-300mm A17老镜头评测:低预算入门长焦的实战指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/4 9:24:38

STM32软件模拟I2C驱动AD7747高精度电容ADC实战

简介&#xff1a;本资源是一套面向嵌入式开发初学者与STM32项目实践者的AD7747电容/电压双通道高精度ADC驱动解决方案&#xff0c;聚焦于无硬件I2C外设或需灵活时序控制场景下的软件模拟I2C通信实现。资源包共9个文件&#xff08;6个C源文件、3个头文件&#xff09;&#xff0c…

作者头像 李华
网站建设 2026/9/4 9:23:58

AI创业者通识日报 | 2026年9月3日

AI创业者通识日报 | 2026年9月3日 今日头条01 OpenAI 新模型 Astra 曝光"循环深度"推理技术&#xff1a;性能或超 GPT-4 级飞跃&#xff0c;但安全监控面临新挑战 头条 前沿模型 据 The Information 报道&#xff0c;OpenAI 即将推出的新模型 Astra 搭载创新推理技术…

作者头像 李华
网站建设 2026/9/4 9:21:20

51单片机驱动nRF24L01实现无线通信:从SPI模拟到协议设计

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/4 9:20:08

Claude Code安装配置与实战指南:AI编程助手集成开发全流程

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华