ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

糖尿病管理Android App源码解析与实战优化

糖尿病管理Android App源码解析与实战优化 简介这是一套面向计算机、数学及电子信息类专业学生的糖尿病管理安卓应用开发实践资源适用于课程设计、期末大作业与毕业设计参考帮助初学者掌握健康类移动应用的核心开发流程与模块集成方法。压缩包共242个文件含88个Java业务逻辑代码、75个XML界面布局与配置文件、50个PNG图标资源辅以SO库、Gradle构建脚本及AAR依赖组件整体体积仅1.75MB结构紧凑、便于快速导入Android Studio运行调试。已有109人下载学习资源提供完整可运行源码及配套项目说明文档涵盖用户登录、血糖记录、趋势图表、用药提醒等核心功能模块代码层次清晰、注释基础完备适合在理解MVC架构基础上进行功能扩展与UI优化。1. 这不是个“健康打卡App”而是一套可落地的糖尿病患者日常管理闭环很多同学拿到这个「糖尿病管理系统安卓app源码」第一反应是又一个课程设计Demo点开发现它真能跑——登录后直接进入血糖记录页支持手动录入拍照识别调用系统相机历史数据自动生成折线图用药提醒用AlarmManagerNotificationChannel实现连Android 8.0以上通知适配都做了。更关键的是它没堆砌炫酷UI而是把「患者每日必做动作」拆解成测血糖→记饮食→看趋势→设提醒→导出PDF报告每个环节都有对应Activity和SQLite本地持久化逻辑。适合计算机/医学信息工程专业学生做毕设也适合刚转Android开发、想补全「医疗类App典型模块链路」的工程师——它不依赖后端纯离线可用但所有模块接口预留了RESTful扩展位如NetworkUtils类里已封装Retrofit基础配置。如果你正卡在「怎么把医学逻辑翻译成Android组件交互」这个项目就是现成的翻译词典。2. 从Gradle构建到Activity生命周期解析糖尿病管理的核心模块链路2.1 构建环境与依赖选型的务实逻辑该项目使用Android Studio 3.6兼容的Gradle 5.6.4见gradlew.bat和gradle/wrapper/gradle-wrapper.properties未升级至AGP 8.x说明作者刻意规避Jetpack Compose等新范式专注解决实际问题。核心依赖集中在app/build.gradle中dependencies { implementation androidx.appcompat:appcompat:1.2.0 implementation com.google.android.material:material:1.3.0 implementation androidx.constraintlayout:constraintlayout:2.0.4 implementation androidx.room:room-runtime:2.2.6 // 本地数据库 implementation androidx.lifecycle:lifecycle-viewmodel:2.2.0 implementation androidx.lifecycle:lifecycle-livedata:2.2.0 implementation androidx.navigation:navigation-fragment:2.3.1 implementation androidx.navigation:navigation-ui:2.3.1 implementation androidx.camera:camera-core:1.0.0-beta07 // 相机模块 implementation androidx.camera:camera-camera2:1.0.0-beta07 implementation androidx.camera:camera-lifecycle:1.0.0-beta07 implementation com.github.bumptech.glide:glide:4.11.2 // 图片加载 implementation com.github.PhilJay:MPAndroidChart:v3.1.0 // 折线图 }注意SMSSDK-2.0.2.aar是独立打包的短信验证SDK非本项目必需若需移除只需删掉app/libs/SMSSDK-2.0.2.aar并在build.gradle中注释掉implementation files(libs/SMSSDK-2.0.2.aar)。该SDK未在代码中调用属于冗余残留。Room数据库设计直击临床需求BloodSugarEntity表含id,date,time,value,type(空腹/餐后/睡前),note字段MedicineEntity表含name,dose,frequency,next_take_timeDietRecordEntity表记录每餐碳水克数和GI值。这种设计跳过复杂ORM映射用Dao接口直接操作新手可快速理解「血糖值如何存、如何查最近7天」。2.2 主流程Activity的职责划分与数据流转整个App采用单Activity多Fragment架构MainActivity为容器导航由Navigation Component驱动。关键Activity/Fragment关系如下组件职责关键技术点LoginActivity用户认证本地账号使用SharedPreferences存储加密后的用户名/密码AES-128密钥硬编码在SecurityUtil.javaHomeFragment数据概览页调用BloodSugarDao.getRecent7Days()获取数据用MPAndroidChart绘制折线图RecordBloodSugarFragment血糖录入页集成CameraX拍照→TextRecognition识别数值→手动修正→保存到RoomMedicineReminderFragment用药提醒AlarmManager设置重复闹钟BroadcastReceiver接收触发NotificationCompat.Builder构建通知以血糖录入为例数据流转路径为RecordBloodSugarFragment→BloodSugarViewModel持有BloodSugarRepository →BloodSugarDao.insert()→ SQLite写入 →LiveData通知UI更新 →HomeFragment自动刷新图表。2.2.1 CameraX拍照识别血糖值的实现细节识别逻辑在RecordBloodSugarFragment.java第187行开始private void startCamera() { ListenableFuturePreview previewFuture cameraProviderFuture.addListener(() - { try { Preview preview new Preview.Builder().build(); preview.setSurfaceProvider(viewFinder.getSurfaceProvider()); ImageAnalysis imageAnalysis new ImageAnalysis.Builder() .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST) .build(); imageAnalysis.setAnalyzer(ContextCompat.getMainExecutor(requireContext()), new TextAnalyzer()); // 自定义文本分析器 cameraProvider.bindToLifecycle(this, cameraSelector, preview, imageAnalysis); } catch (Exception e) { Log.e(CameraX, Use case binding failed, e); } }, ContextCompat.getMainExecutor(requireContext())); }TextAnalyzer继承ImageAnalysis.Analyzer在analyze()方法中调用TextRecognition.getClient(TextRecognizerOptions.DEFAULT_OPTIONS)获取Google ML Kit文本识别实例。识别结果经正则过滤Pattern.compile(\\d\\.?\\d*)提取数字再通过BloodSugarValidator.isValidValue()校验范围3.9–25.0 mmol/L。关键参数说明ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST防止图像堆积导致OOMTextRecognizerOptions.DEFAULT_OPTIONS启用设备端OCR无需网络请求。2.3 SQLite本地数据库的健壮性设计DatabaseClient.java采用单例模式初始化Room数据库关键配置如下public static DatabaseClient getInstance(Context context) { if (instance null) { instance Room.databaseBuilder(context.getApplicationContext(), DatabaseClient.class, diabetes_db) .fallbackToDestructiveMigration() // 开发阶段允许表结构变更 .addCallback(roomCallback) // 数据库创建/升级回调 .build(); } return instance; }roomCallback在onCreate()中预置3条测试血糖数据避免首次启动空白onOpen()中执行PRAGMA journal_mode WAL提升并发写入性能。BloodSugarDao接口示例Dao public interface BloodSugarDao { Insert(onConflict OnConflictStrategy.REPLACE) long insert(BloodSugarEntity entity); Query(SELECT * FROM blood_sugar WHERE date :startDate AND date :endDate ORDER BY date DESC, time DESC) LiveDataListBloodSugarEntity getRange(String startDate, String endDate); Query(SELECT AVG(value) FROM blood_sugar WHERE type 空腹 AND date date(now, -30 days)) float getFastingAvgLast30Days(); // 直接聚合查询减少内存计算 }提示fallbackToDestructiveMigration()仅用于开发上线前必须替换为addMigrations()并编写迁移脚本如MIGRATION_1_2将blood_sugar表新增unit字段。3. 功能增强实战为血糖记录添加饮食关联与趋势预警3.1 在血糖记录中绑定饮食数据原项目中血糖与饮食记录完全独立。要实现「测完血糖后一键关联当餐饮食」需修改RecordBloodSugarFragment布局和逻辑在activity_record_blood_sugar.xml底部添加饮食选择按钮Button android:idid/btn_link_diet android:layout_widthmatch_parent android:layout_heightwrap_content android:text关联今日饮食 android:layout_marginTop16dp/在RecordBloodSugarFragment.java中绑定点击事件btnLinkDiet.setOnClickListener(v - { // 查询今日所有饮食记录 dietRepository.getTodayDietRecords().observe(getViewLifecycleOwner(), records - { if (records.isEmpty()) { Toast.makeText(getContext(), 今日暂无饮食记录, Toast.LENGTH_SHORT).show(); return; } // 弹出选择对话框 showDietSelectionDialog(records); }); });创建DietLinkDialog.java显示RecyclerView列表用户选择后执行// 关联逻辑更新BloodSugarEntity的diet_id外键 bloodSugarEntity.setDietId(selectedDiet.getId()); bloodSugarRepository.update(bloodSugarEntity);对应数据库变更在BloodSugarEntity中新增ColumnInfo(name diet_id) public long dietId;并在BloodSugarDao中添加Query(UPDATE blood_sugar SET diet_id :dietId WHERE id :bloodId)。3.2 基于移动平均线的趋势预警算法原MPAndroidChart仅显示原始数据点。要添加「连续3天空腹血糖7.0mmol/L触发预警」需在HomeFragment.java中增强图表逻辑private void setupChart() { LineData lineData new LineData(); // ... 原始数据添加逻辑 // 计算3日移动平均线 ListEntry ma3Entries calculateMovingAverage(bloodSugarList, 3); LineDataSet ma3Set new LineDataSet(ma3Entries, 3日均值); ma3Set.setColor(Color.RED); ma3Set.setLineWidth(2f); ma3Set.setDrawValues(false); // 不显示数值标签 // 添加预警线7.0 mmol/L LineDataSet alertSet new LineDataSet(new ArrayList(), 预警线); alertSet.setColor(Color.parseColor(#FF6B6B)); alertSet.setLineWidth(1.5f); alertSet.setValueTextColor(Color.parseColor(#FF6B6B)); // 检查是否触发预警 boolean isAlert false; for (int i 2; i ma3Entries.size(); i) { if (ma3Entries.get(i).getY() 7.0f) { isAlert true; break; } } if (isAlert) { showAlertNotification(); // 发送系统通知 } lineData.addDataSet(ma3Set); lineData.addDataSet(alertSet); chart.setData(lineData); }calculateMovingAverage()方法遍历bloodSugarList对每个时间点取前N个同类型空腹记录计算均值。参数说明移动窗口大小3代表临床常用的「短期趋势观察」阈值7.0依据《中国2型糖尿病防治指南》空腹血糖控制目标设定。3.3 导出PDF报告的完整实现ExportReportActivity.java使用PdfDocument生成带图表的PDFprivate void generatePdf() { PdfDocument document new PdfDocument(); PdfDocument.Page page document.startPage(new PageInfo.Builder(1000, 1414, 1).create()); // A4尺寸 Canvas canvas page.getCanvas(); // 绘制标题 TextPaint titlePaint new TextPaint(); titlePaint.setTextSize(24f); canvas.drawText(糖尿病管理周报, 100, 150, titlePaint); // 将图表转为Bitmap并绘制 chart.setDrawingCacheEnabled(true); Bitmap chartBitmap chart.getDrawingCache(); canvas.drawBitmap(chartBitmap, 100, 200, null); // 写入文字摘要 TextPaint summaryPaint new TextPaint(); summaryPaint.setTextSize(16f); String summary String.format(本周平均空腹血糖%.1f mmol/L\n最高值%s\n最低值%s, avgFasting, maxFastingDate, minFastingDate); canvas.drawText(summary, 100, 200 chartBitmap.getHeight() 50, summaryPaint); document.finishPage(page); savePdfToFile(document); }注意chart.getDrawingCache()需在chart.setDrawingCacheEnabled(true)后立即调用否则返回nullA4尺寸1000×1414像素72dpi确保打印清晰度。4. 排错与性能优化解决Android 10存储权限与图表渲染卡顿4.1 Android 10分区存储适配方案项目默认使用getFilesDir()存储PDF报告但在Android 10API 29强制分区存储下Environment.getExternalStorageDirectory()已废弃。修复步骤在AndroidManifest.xml中声明application android:requestLegacyExternalStoragetrue !-- 临时兼容方案 -- ... 更彻底的适配改用Context.getExternalFilesDir(Environment.DIRECTORY_DOCUMENTS)private File getExportDir() { File dir getExternalFilesDir(Environment.DIRECTORY_DOCUMENTS); if (!dir.exists()) dir.mkdirs(); return dir; } private void savePdfToFile(PdfDocument document) { File file new File(getExportDir(), diabetes_report_ System.currentTimeMillis() .pdf); try (FileOutputStream fos new FileOutputStream(file)) { document.writeTo(fos); Toast.makeText(this, 报告已保存至 file.getAbsolutePath(), Toast.LENGTH_LONG).show(); } catch (IOException e) { Log.e(PDF, Save failed, e); } }4.2 MPAndroidChart渲染卡顿的3种优化手段当血糖记录超200条时图表滑动明显卡顿。根本原因是LineDataSet默认启用setDrawCircles(true)绘制每个数据点圆圈。优化方案优化项实施代码效果关闭数据点圆圈lineDataSet.setDrawCircles(false);减少GPU绘制节点帧率提升40%启用硬件加速chart.setLayerType(View.LAYER_TYPE_HARDWARE, null);利用GPU缓存图表纹理限制显示点数chart.setVisibleXRangeMaximum(30);滑动时只渲染可见区域30个点在HomeFragment.java中整合chart.setLayerType(View.LAYER_TYPE_HARDWARE, null); chart.setVisibleXRangeMaximum(30); chart.getXAxis().setGranularity(1f); // X轴最小间隔为1天 chart.getAxisLeft().setGranularity(0.1f); // Y轴最小间隔0.1mmol/L4.3 AlarmManager用药提醒失效的调试清单部分用户反馈「用药提醒不触发」常见原因及验证方法问题类型检查命令/步骤修复方式应用被系统休眠adb shell dumpsys battery关闭省电模式或添加白名单通知渠道未创建adb shell cmd notification list确保MedicineReminderReceiver.java中createNotificationChannel()执行Alarm时间精度不足adb shell dumpsys alarm | grep -A5 your_package_name改用setExactAndAllowWhileIdle()替代setRepeating()验证Alarm是否注册成功adb shell dumpsys alarm \| grep com.diabetesmanage # 输出应包含类似RTC_WAKEUP #0: Alarm{...} tag*** your_package_name若无输出检查MedicineReminderHelper.java中alarmManager.setRepeating()调用时机——必须在Application.onCreate()或MainActivity.onResume()中执行且PendingIntent的FLAG_IMMUTABLE标志需适配Android 12。5. 从源码到生产四大关键参数的定制化修改指南5.1 临床指标阈值的集中配置管理所有血糖/血压/体重预警阈值分散在各处如HomeFragment硬编码7.0MedicineReminderHelper中用药间隔写死24小时。统一改为Constants.javapublic class Constants { public static final float FASTING_GLUCOSE_HIGH 7.0f; // 空腹高血糖阈值 public static final float POSTPRANDIAL_GLUCOSE_HIGH 10.0f; // 餐后高血糖阈值 public static final int MEDICINE_REMINDER_INTERVAL_MIN 60; // 最小提醒间隔分钟 public static final String DATABASE_NAME diabetes_db; public static final int DATABASE_VERSION 2; }后续所有引用处替换为Constants.FASTING_GLUCOSE_HIGH。优势修改阈值只需改一处避免漏改导致逻辑矛盾便于后期对接医院HIS系统动态下发阈值。5.2 图表主题与配色的快速切换表MPAndroidChart默认蓝绿色系不符合医疗App严肃感。预设三套配色方案方案主色适用场景修改位置临床蓝#2196F3标准版HomeFragment.java中lineDataSet.setColor()温暖橙#FF9800老年版高对比度colors.xml新增colorPrimaryOrange无障碍灰#616161视力障碍版app/src/main/res/values-night/colors.xml切换逻辑在SettingsActivity中实现String theme sharedPrefs.getString(theme, clinical_blue); switch (theme) { case warm_orange: lineDataSet.setColor(ContextCompat.getColor(this, R.color.colorPrimaryOrange)); break; case accessibility_gray: lineDataSet.setColor(ContextCompat.getColor(this, R.color.colorPrimaryGray)); break; }5.3 APK签名与发布前的必检项清单课程设计可直接运行但作为真实医疗工具发布需严格校验检查项命令/操作说明签名验证jarsigner -verify -verbose -certs app-release.apk确认使用v1/v2签名权限最小化aapt dump permissions app-release.apk移除READ_SMS等无关权限敏感信息扫描grep -r password|key|secret app/src/硬编码密钥需替换为Keystore方法数统计./gradlew app:dependencies --configuration releaseRuntimeClasspath确保未超64K方法限制特别注意SecurityUtil.java中AES密钥diabetes_key_2023必须替换为Keystore生成的密钥对否则逆向工具可直接提取。5.4 适配Android 12 SplashScreen API的渐进式改造Android 12要求使用SplashScreenAPI否则启动白屏。改造步骤在res/values/themes.xml中定义style nameTheme.DiabetesManage.Splash parentTheme.SplashScreen item namewindowSplashScreenBackgroundcolor/splash_background/item item namewindowSplashScreenAnimatedIcondrawable/ic_launcher_foreground/item item namepostSplashScreenThemestyle/Theme.DiabetesManage/item /styleAndroidManifest.xml中MainActivity主题改为activity android:name.MainActivity android:themestyle/Theme.DiabetesManage.Splash ... MainActivity.java中移除setContentView()改为Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); SplashScreen splashScreen SplashScreen.installSplashScreen(this); setContentView(R.layout.activity_main); }此改造不影响低版本且SplashScreen自动处理图标缩放和动画比自定义SplashActivity更稳定。本文还有配套的精品资源点击获取
返回列表