news 2026/9/15 5:46:57

Android多方交互慢病管理App开发实战:从SQLite到通知权限

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Android多方交互慢病管理App开发实战:从SQLite到通知权限

简介:基于安卓的多方交互老年人慢病管理App开发项目,面向安卓开发学习者、课程设计与毕业设计人员。项目采用安卓与Java技术栈,实现医生端与患者端双角色完整功能:医生端涵盖患者档案、慢病管理、在线交流与健康资讯,便于医生维护患者信息与推送管理建议;患者端支持在线咨询、健康报告、电子病历及特别提醒,帮助老年用户及其家属便捷查看健康数据。系统通过多方交互设计,连接医生、患者与家属,实现慢病管理的远程协作与信息同步。压缩包共1204个文件,大小16.03MB,包含Java源码、Vue前端页面、XML配置、PNG图片及SQL数据库脚本等;Java文件承担Android业务逻辑,Vue用于后台管理界面,SQL为数据库初始化脚本,并附有说明文档辅助理解与部署。当前已有113人学习。资源提供完整源码、数据库与说明,可直接导入开发环境运行,也可按模块二次开发,适合作为课程设计、毕业设计或慢病管理项目实战的参考范例。

1. 这个 Android 慢病管理 App 到底要交什么活

把“基于 Android 的多方交互的老年人慢病管理 App 开发”压缩成一句话,就是以慢病数据为中心的多人协同工具:老年人在 Android 端录入血压、血糖、用药记录,子女或社区医生能远程看到趋势并及时收到提醒。拿到手的是“源码 + 数据库 + 说明”的打包素材,交差之前要想清楚,验收时真正看的不是图标好不好看,而是当场演示时数据真的落到了 SQLite,提醒真的弹得出来。

App 开发入门者容易把“多方交互”想成聊天室,这是最典型的跑偏。多方交互在课程设计语境下,通常只是三个角色、两种查看权限和一条异常判断链路:患者管录入,子女管查看,医生管建议。本文按这个口径把结构、建表、代码通讯和收尾逐一展开,排除掉需要真实短信或云服务的复杂方案,保证一台 Android 模拟器就能跑通。

2. 多方交互模型选型:为什么不是多对多聊天,而是主要照顾者模式

2.1 三种交互模型的对比与判定:你手里的源码更接近哪一种

“多方交互”在需求文档里往往只有一句话,落到设计上却有三种明显不同的模型。第一种是一对一提醒型,App 只有患者和系统两个端点,系统按时间表发通知,患者被动接收。第二种是主要照顾者模式,患者、子女、医生三方参与,子女承担日常监督,医生只在数据异常时介入。第三种是多对多社区型,类似社交平台,患者之间互相点赞、评论、共享经验。

课程设计和毕业设计里最常见的是一对一提醒型或主要照顾者模式,后者更贴合标题里的“多方交互”。判断方法很简单:看数据库里有没有一张包含 relation_type 字段的关系表,以及看提醒触发后是否有第二个人能收到同样的通知。

模型角色数数据流向实现成本典型功能
一对一提醒型1患者 → 本地数据库用药提醒、记录查询
主要照顾者模式3患者录入,子女/医生查看家庭绑定、趋势分享、异常通知
多对多社区型全员互相可见动态、评论、点赞、搜索

选择主要照顾者模式的原因很实在:老年人慢病管理的核心矛盾不是“记录不够多”,而是“记录没人看”。让子女通过同一个 App 查看曲线,比让老人主动转发截图更可靠,也避开了实时聊天和高并发带来的工程复杂度。角色少,权限边界就清晰,期末答辩时也更容易讲清楚“谁有什么权限、为什么这样设计”。

2.1.1 角色与权限的最小建模

先不急着写界面,把角色定义成代码里的枚举或常量。常见做法是在 user 表里存 role 字段,在 family_relation 表里存关系类型。

data class User( val userId: Long, val username: String, val role: String, // PATIENT / CAREGIVER / DOCTOR val relationType: String // SELF / FAMILY / MEDICAL )

role 决定页面入口,relationType 决定可见范围。比如同样是 CAREGIVER,relationType 为 FAMILY 的只能看到绑定老人的数据,看不到其他患者记录。这不是多余设计,而是评审老师最容易追问的地方:如果没有这张关系表,任何登录用户都能查看全部健康记录,权限设计直接不合格。

2.2 权限边界与通知机制:Android 端交互的三个做法

多方交互在移动端的落地点不只是权限,还有通知机制。同一台手机上,“患者录入完成”和“子女需要知道异常”这两个事件,依赖本地通知就能完成闭环,不需要服务器参与。

通知链路的三步做法是:先建 NotificationChannel,再构造 NotificationCompat.Builder,最后通过 NotificationManagerCompat.notify 发出。下面这段代码是提醒模块的最小实现,可直接放进工具类。

fun sendReminder(context: Context, reminder: Reminder) { val channelId = "medication_reminder" val manager = NotificationManagerCompat.from(context) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { val channel = NotificationChannel( channelId, "用药提醒", NotificationManager.IMPORTANCE_HIGH ) manager.createNotificationChannel(channel) } val intent = Intent(context, ReminderDetailActivity::class.java) intent.putExtra("reminder_id", reminder.id) val pendingIntent = PendingIntent.getActivity( context, reminder.id, intent, PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT ) val notification = NotificationCompat.Builder(context, channelId) .setSmallIcon(R.drawable.ic_notify) .setContentTitle("用药提醒") .setContentText("${reminder.drugName} ${reminder.dosage}") .setContentIntent(pendingIntent) .setAutoCancel(true) .build() if (ActivityCompat.checkSelfPermission( context, Manifest.permission.POST_NOTIFICATIONS ) == PackageManager.PERMISSION_GRANTED ) { manager.notify(reminder.id, notification) } }

这段代码里有几个参数值得注意。channelId 必须是常量,不能每次调用都 new 一个字符串,否则通知渠道会重复创建。PendingIntent.FLAG_IMMUTABLE 是 Android 12 之后的强制要求,漏掉会直接崩溃。POST_NOTIFICATIONS 是 Android 13 新增的运行时权限,旧版项目如果只配置了 Manifest 没做运行时申请,在 Android 13 以上机型会静默失败。

3. 用 Android Studio 搭出项目骨架:权限、依赖与页面入口

3.1 创建工程与权限配置:三个必填的 Manifest 项

用 Android Studio 新建项目时选 Empty Views Activity,语言选 Kotlin,minSdk 设到 24 或 26 均可,targetSdk 建议跟着当前稳定版走。模拟器直接用 Android Studio 自带的 AVD,选 Pixel 系列镜像,比折腾第三方模拟器省时间。新版 Android Studio 里可以通过 Settings 的 Plugins 菜单切换中文语言包,对初次接触 Android 工程结构的读者更友好。

AndroidManifest.xml 里三个权限项不能少:

<uses-permission android:name="android.permission.POST_NOTIFICATIONS" /> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> <uses-permission android:name="android.permission.INTERNET" />

POST_NOTIFICATIONS 是通知权限,Android 13 以上必须动态申请。RECEIVE_BOOT_COMPLETED 用来支持重启手机后恢复用药提醒,没有它在开发时感觉不到问题,真机重启后所有闹钟都会丢。INTERNET 权限在纯本地项目里看似没用,但后面做趋势图加载或升级成服务端同步时会用到,提前写上省得改。运行时申请代码放在 MainActivity 的 onCreate 里,用 ActivityResultContracts.RequestPermission 即可。

3.2 Gradle 依赖的三个固定版本

依赖版本建议固定,不要用动态版本号。课程设计最大的坑不是依赖冲突,而是版本号漂移导致的问题无法复现。下面三行是慢病管理 App 最常用的依赖,写在模块级 build.gradle 的 dependencies 里。

implementation 'androidx.appcompat:appcompat:1.6.1' implementation 'com.google.android.material:material:1.11.0' implementation 'com.github.PhilJay:MPAndroidChart:v3.1.0'

appcompat 和 material 提供页面控件与主题样式,MPAndroidChart 用来画血压、血糖趋势折线图。v3.1.0 是 MPAndroidChart 最稳定的公开版本,后续项目里直接引用这个版本不会出现兼容性问题。加完依赖后 Sync 一次,如果下载超时,检查 Gradle JDK 版本是否和 Android Studio 要求一致。

3.3 页面入口与角色跳转

页面结构按角色拆:登录页 → 患者首页 → 记录页 / 趋势页 / 家庭绑定页;子女登录则直接进入所绑定患者的趋势页。跳转用 Intent 传值即可,不引入 Navigation 组件,答辩时更容易解释。

val intent = Intent(this, TrendActivity::class.java).apply { putExtra("targetUserId", currentUserId) putExtra("viewerRole", "CAREGIVER") } startActivity(intent)

currentUserId 在登录成功后写入 SharedPreferences,后续所有查询都以它为条件。viewerRole 决定趋势页顶部是否显示“异常通知”按钮,这是多方交互在 UI 层的第一道卡口。

4. 数据库表结构设计与 SQLite 增量建档方案

4.1 三张核心表的字段设计与建表语句

慢病管理 App 的数据库不需要复杂建模,三张表足够:user 存用户,health_record 存健康指标,medication_reminder 存用药计划。其中 health_record 是数据量最大的表,每次测量生成一条记录,频繁插入和按时间查询是主要压力。

CREATE TABLE user ( id INTEGER PRIMARY KEY AUTOINCREMENT, username TEXT NOT NULL UNIQUE, password TEXT NOT NULL, role TEXT NOT NULL DEFAULT 'PATIENT', relation_type TEXT NOT NULL DEFAULT 'SELF', invite_code TEXT ); CREATE TABLE health_record ( id INTEGER PRIMARY KEY AUTOINCREMENT, user_id INTEGER NOT NULL, record_type TEXT NOT NULL, value REAL NOT NULL, unit TEXT DEFAULT '', measure_time INTEGER NOT NULL, note TEXT DEFAULT '', FOREIGN KEY (user_id) REFERENCES user(id) ); CREATE TABLE medication_reminder ( id INTEGER PRIMARY KEY AUTOINCREMENT, user_id INTEGER NOT NULL, drug_name TEXT NOT NULL, dosage TEXT DEFAULT '', hour INTEGER NOT NULL, minute INTEGER NOT NULL, enabled INTEGER DEFAULT 1, FOREIGN KEY (user_id) REFERENCES user(id) );

record_type 用 TEXT 而不是单独建指标字典表,是因为血压、血糖、心率这些类型的数量在项目周期内基本固定,拆表反而增加 JOIN 复杂度。measure_time 存 Unix 毫秒时间戳,排序和区间查询都比字符串高效。medication_reminder 里的 hour 和 minute 拆开存,方便 AlarmManager 直接读取,不用解析字符串。

4.2 用 SQLiteOpenHelper 实现增量建档

“增量建档”指的是 App 首次启动时创建表并写入基础数据,后续启动只检查版本号,不重复建表。实现方式是 SQLiteOpenHelper 的 onUpgrade 里用版本号控制,但课程设计阶段更常见的是 onUpgrade 里直接 DROP TABLE 重建,这种做法会丢数据,不适合慢病记录场景。

class HealthDbHelper(context: Context) : SQLiteOpenHelper(context, "health.db", null, 2) { override fun onCreate(db: SQLiteDatabase) { db.execSQL(CREATE_USER_TABLE) db.execSQL(CREATE_RECORD_TABLE) db.execSQL(CREATE_REMINDER_TABLE) insertDefaultDict(db) } override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) { if (oldVersion < 2) { db.execSQL("ALTER TABLE user ADD COLUMN invite_code TEXT") } } private fun insertDefaultDict(db: SQLiteDatabase) { val values = ContentValues().apply { put("username", "admin") put("password", "123456") put("role", "DOCTOR") put("relation_type", "MEDICAL") } db.insert("user", null, values) } }

onCreate 只调用一次,适合放建表语句和默认管理员账号。onUpgrade 里用 if 分支而不是 DROP 重建,保证用户升级 App 后历史记录还在。数据库版本号从 1 增加到 2 时,新加的 invite_code 字段通过 ALTER TABLE 补上,这是 Android 数据库迁移的标准姿势。

4.3 同步与备份的取舍:为什么不建议在课程设计阶段做远程同步

看到“数据库 + 多方交互”两个词,很容易联想到 MySQL 和服务端接口。但从课程设计的验收标准来看,远程同步的性价比很低:网络不稳定、联调耗时、答辩现场可能没网。数据库同步工具确实能解决部分问题,但引入第二套系统会让整个项目的复杂度翻倍。

方案优点缺点适合场景
纯 SQLite简单可靠,离线可用数据只在单机完整记录与查询功能
CSV/JSON 导出用户可自行分享不自动、需手动数据备份与交作业
FTP/网盘同步实现简单安全性差不推荐
服务端 API真正多方实时共享需要服务器与联调毕业后扩展方向

如果必须展示“多方”,可以用 App 内的家庭组模拟远程:子女账号登录后查询同一 SQLite 数据库。等到答辩时再口头说明“生产环境会替换为服务端”,这是最稳妥的路径。

5. 多方交互的两个核心动作:家庭绑定与健康数据回传

5.1 家庭绑定实现:邀请码的生成与校验流程

多方交互的第一个动作是把两个账号绑定到一个家庭组。不做实时通信,通过邀请码完成绑定是最常见的离线方案:患者手机生成六位邀请码,子女在 App 里输入邀请码完成绑定。

fun generateInviteCode(seed: Long): String { val chars = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789" val sb = StringBuilder() var v = seed repeat(6) { sb.append(chars[(v % chars.length).toInt()]) v /= chars.length } return sb.toString() }

邀请码字符集去掉了 I、O、0、1,避免老人输入时混淆。seed 用当前毫秒时间戳或 userId 均可,时间戳生成的结果更随机。绑定流程是:患者端显示 invite_code,子女端输入后,在 family_relation 表插入一条记录,双方关系即建立。

5.1.1 绑定关系写库代码
fun bindFamily(db: SQLiteDatabase, caregiverId: Long, patientId: Long) { val values = ContentValues().apply { put("caregiver_id", caregiverId) put("patient_id", patientId) put("relation_type", "FAMILY") put("bind_time", System.currentTimeMillis()) } db.insert("family_relation", null, values) }

family_relation 表在上一章的建表语句里没有出现,这是刻意的:先把核心三张表跑通,再按模块追加关系表。bind_time 字段用来处理“解绑后再绑定”的时间线问题,按最新 bind_time 查询有效关系即可。

5.2 让子女看到趋势:MPAndroidChart 折线图接入

多方交互的第二个动作是健康数据回传。在不做服务端的前提下,回传的含义是子女登录后能立即看到同一数据库里老人的血压曲线。折线图比数值列表更直观,也更有答辩效果。

val chart = findViewById<LineChart>(R.id.chart) chart.description.isEnabled = false val entries = records.mapIndexed { index, r -> Entry(index.toFloat(), r.value.toFloat()) } val dataSet = LineDataSet(entries, "收缩压").apply { mode = LineDataSet.Mode.CUBIC_BEZIER color = Color.rgb(233, 84, 82) setCircleColor(Color.rgb(233, 84, 82)) lineWidth = 2f } chart.data = LineData(dataSet) chart.invalidate()

mode 设为 CUBIC_BEZIER 会生成平滑曲线,但数据点少于五个时曲线会明显失真,所以建议只在查询结果超过三条时启用。加载趋势图时,数据量小可以不加进度条,但如果设计成模拟网络加载,用 MaterialProgressBar 包裹图表区域会更接近真实 App 的体验。

5.3 异常阈值的判定规则:谁来判断、怎么提醒

数据回传后不能只展示,还要有判定。判断逻辑放在查询层而不是 UI 层,确保老人端和子女端看到的是同一套结果。

指标正常范围异常阈值
收缩压90–140(mmHg)≥ 180 或 ≤ 80
舒张压60–90(mmHg)≥ 110
空腹血糖3.9–6.1(mmol/L)≥ 7.0
静息心率60–100(次/分)≥ 120

判定代码在插入记录时执行,命中后走通知渠道发送告警:

fun checkAbnormal(recordType: String, value: Float): Boolean { return when (recordType) { "blood_pressure_systolic" -> value >= 180f || value <= 80f "blood_pressure_diastolic" -> value >= 110f "blood_glucose" -> value >= 7.0f "heart_rate" -> value >= 120f else -> false } }

这里特意把阈值写死在代码里,而不是放在数据库配置表,是因为在课程设计阶段,一份可读的判断方法比可配置系统更容易被评审接受。后续升级方向是改成从数据库读取阈值,但那是“系统设计”层面的加分项,不是必选项。

6. 上架与调试前的三个收尾技巧:日志验证、正式签名与发布成本

6.1 用 Logcat 和 dumpsys 验证交互链路

功能写完先别急着装真机,用日志验证数据链路能省掉大量 UI 调试时间。在插入 health_record 和发送通知的代码位置各加一行 Log.d,然后用 adb 命令过滤。

adb logcat -s HealthApp:D adb shell dumpsys notification --noredact | grep 用药提醒

-s HealthApp:D只显示 HealthApp 标签下的 Debug 日志。dumpsys 命令直接读系统通知服务,能看到通知是否真的发出。如果 logcat 显示插入成功但 dumpsys 里没有通知,优先查 POST_NOTIFICATIONS 运行时权限是否已授予。

6.2 正式签名与版本号:最容易漏的一步

调试模式安装的 App 用的是 debug 签名,换一台手机就会因签名不一致无法覆盖安装。生成正式签名的命令是:

keytool -genkeypair -v -keystore healthapp.jks -keyalg RSA -keysize 2048 -validity 10000 -alias healthapp

生成后修改模块级 build.gradle 的 signingConfigs,把 storeFile 指到 jks 文件路径,然后执行 assembleRelease 打包。这里要留意一点:签署文件名和别名不要用默认值,防止后续换电脑时搞混密钥。

6.3 上架成本与发布检查清单

把“开发一个 App 并上架大概要多少钱”换成维护成本看会更清楚:课程作业阶段只需要真机安装验证,不需要也尽量不要上架。国内应用商店对医疗健康类 App 的资质审核很严格,个人开发者很难走通,且各商店政策不同,成本和周期不可控。

场景签名要求服务器成本
模拟器验收调试签名即可0
真机演示正式签名更稳妥0
应用市场上架正式签名 + 软著/资质视功能而定需要提前评估

上架不是这个项目的终点,把 assembleRelease 产出的 APK 装到老人手机上,再用返回键退出 App 后重新进入,确认提醒记录仍然存在,才算是把多方交互的最后一环接上。

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

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

从静态HTML模板到OA后台管理系统改造实践指南

简介&#xff1a;数字化企业OA后台管理系统网页静态模板聚焦OA后台界面搭建&#xff0c;适合前端开发人员、高校学生及需要快速产出后台原型的项目团队使用。压缩包约1.9MB&#xff0c;覆盖登录、首页、导航栏、表格、表单等核心页面&#xff0c;将HTML结构、CSS样式与JavaScri…

作者头像 李华
网站建设 2026/9/15 5:43:40

新手入门必看:做pc端的网站首页尺寸是多少及避坑指南

新手入门必看:做pc端的网站首页尺寸是多少及避坑指南 很多刚接触网页设计的朋友,第一反应不是问布局,而是拿着尺子量屏幕。这很正常,但如果你只盯着“1920”或者“1366”这两个数字,那你的网站上线后大概率会翻车。更让人头疼的是,当网站尺寸定下来后,很多新手发现服务器响应慢、图片加载不出来,甚至域名…

作者头像 李华
网站建设 2026/9/15 5:42:42

从龙虾养殖到AGI原型:技术演进与前沿探索

1. 从龙虾养殖到AGI原型&#xff1a;一场技术革命的隐喻最近在技术社区看到一个有趣的标题对比&#xff1a;"当大家还在养龙虾时&#xff0c;Andrej Karpathy可能已经构建出了AGI原型"。这个看似戏谑的对比&#xff0c;实际上揭示了技术发展中的关键现象——当大多数…

作者头像 李华
网站建设 2026/9/15 5:40:33

iOS应用生命周期:从@main到SceneDelegate的底层解析

1. 从“Hello World”到真机运行&#xff1a;iOS开发新手真正该踩的第一个坑 你打开Xcode&#xff0c;新建一个iOS项目&#xff0c;点击Run&#xff0c;模拟器弹出来&#xff0c;屏幕上赫然写着“Hello, World!”——恭喜&#xff0c;你完成了iOS开发的“第一行代码”。但等等…

作者头像 李华
网站建设 2026/9/15 5:40:28

OFDM技术原理与MATLAB实现详解

1. OFDM技术初探&#xff1a;从理论到MATLAB实践正交频分复用&#xff08;OFDM&#xff09;技术是现代无线通信系统的核心技术之一&#xff0c;广泛应用于4G/5G、Wi-Fi、数字电视等领域。这种技术通过将高速数据流分配到多个相互正交的子载波上传输&#xff0c;有效解决了多径效…

作者头像 李华