news 2026/9/4 20:50:52

Android健康管理App开发:从MVVM架构到Room数据库的毕业设计实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Android健康管理App开发:从MVVM架构到Room数据库的毕业设计实战

简介:本资源是一套面向高校计算机及相关专业本科生的Android毕业设计完整实践方案,聚焦个人健康管理场景,解决学生在毕业项目中缺乏可运行、可交付、可答辩的移动端应用原型问题。资源包含253个文件,涵盖57个Java核心逻辑代码、79个XML界面与配置文件、32个PNG图标资源及15个SO本地库等,完整呈现从UI搭建、数据管理到健康指标可视化的一站式开发结构,压缩包仅14.31MB,轻量易部署。已有40人下载学习,适用于毕业设计开题、中期演示及终期提交,亦可作为Android课程设计或期末综合实训参考。用户可直接导入Android Studio运行调试,配套文档含需求分析、系统设计、测试用例与答辩要点,源码已通过真机与模拟器双重验证,结构清晰、注释规范,关键模块如运动记录、睡眠分析、饮食日志均具备完整业务闭环。

1. 项目概述:从毕业设计到可复用的健康管理工具

最近几年,身边不少计算机相关专业的朋友和学生都在为毕业设计发愁,尤其是Android开发方向的。一个常见的困境是:选题既要体现技术综合性,又要有实际应用价值,还不能太脱离个人能力范围。我注意到,“个人健康管理”这个主题出现的频率越来越高。这背后反映了一个趋势:随着大家对自身健康数据的关注度提升,一个能整合记录、分析、提醒功能的手机应用,确实是个“小而美”的切入点。它不像电商或社交应用那样庞大复杂,但足以串联起Android开发的多个核心知识点。

这个“Android平台健康管家系统”项目,就是一个非常典型的毕业设计选题。它听起来不复杂——不就是做个记录体重、步数、睡眠的App嘛。但真要把它做扎实,做出亮点,里面门道可不少。你得考虑数据怎么存(SQLite还是Room?),图表怎么画(MPAndroidChart用起来顺手吗?),后台服务怎么保活(WorkManager还是AlarmManager?),还得设计一套清晰易懂的界面。更重要的是,作为毕业设计,你不仅需要能跑起来的源码,还得有一份逻辑严密、论述清晰的文档,来向导师展示你的设计思路和实现过程。

我拆解过不少类似的项目,也指导过一些同学。这个项目的价值在于,它是一套完整的、可落地的解决方案。你拿到的不只是零散的代码片段,而是一个从需求分析、技术选型、数据库设计、界面实现到数据可视化的完整闭环。无论是用于学习Android开发的最佳实践,还是直接作为毕业设计的基础框架进行二次开发,都非常合适。接下来,我就以一个“过来人”的视角,把这个项目的里里外外、关键技术和容易踩的坑,给你彻底讲明白。

2. 项目核心需求与功能模块拆解

做一个健康管家,首先得想清楚它到底要管什么。我们不能陷入“功能堆砌”的误区,觉得什么都能记就是好。一个好的毕业设计项目,功能模块应该精炼、有逻辑关联,并且能充分展示你的技术能力。

2.1 核心用户需求分析

抛开花哨的概念,用户(也是你答辩时的评委)最关心什么?我总结为三点:记录要方便、数据要直观、提醒要贴心

  1. 便捷记录:用户不可能每天打开App花10分钟填写各种表单。核心健康数据(如步数、体重、睡眠时长)的录入必须极其简单,最好能支持一键快速记录、语音输入,甚至与手机系统健康数据(如Google Fit)同步。
  2. 直观可视化:一堆数字是苍白的。用户需要看到趋势——我这周步数是上升还是下降?体重曲线有没有达到预期?这就要求应用必须有强大的图表展示能力,折线图、柱状图是最基本的要求。
  3. 智能提醒与洞察:这是体现应用“智能”和设计深度的关键。不是简单的“该喝水了”闹钟,而是基于记录的数据,给出个性化的反馈。例如,连续三天睡眠不足6小时,App可以推送提醒:“近期睡眠时间较短,建议今晚提前休息”;或者当体重下降趋势达到预设目标时,给予鼓励。

基于这三点,我们可以把功能模块具体化。

2.2 四大核心功能模块设计

一个结构清晰的健康管家,可以划分为以下四个主要模块,这也在毕业设计文档的“系统设计”章节中需要重点阐述的。

1. 用户中心与数据看板模块这是应用的“门面”。用户一打开App,首先应该看到一个信息丰富的仪表盘(Dashboard)。这里需要聚合显示当日的关键数据概览:今日步数、当前体重、昨晚睡眠时长,并以简洁的图表(例如,过去7天的步数趋势迷你图)展示短期变化。这个模块的技术重点是数据聚合查询自定义View图表库的运用,用来创建这个一目了然的首屏。

2. 健康数据记录模块这是数据的“入口”。需要为不同类型的健康数据设计不同的录入界面。

  • 身体指标:体重、身高、血压(收缩压/舒张压)。界面需要包含数值输入、单位选择和记录时间(通常默认为当前,但允许修改历史记录)。这里涉及EditTextNumberPickerDatePicker等控件的组合使用。
  • 运动数据:步数、运动时长(如跑步、骑行)。步数可以通过SensorManager监听传感器实现,但更实际的方法是使用Health ConnectAPI(Android 14+)或Google FitAPI来读取系统已收集的数据,这能体现你对Android系统级API的理解。
  • 生活习惯:饮水杯数、睡眠时间。睡眠记录比较特殊,手动记录体验差,可以考虑接入手机自带的睡眠检测数据(如果设备支持),或设计一个简单的“上床时间/起床时间”选择器。

注意:记录模块的设计哲学是“为每一条记录打上时间戳”。无论是体重还是饮水量,都必须关联具体的日期和时间,这是后续进行趋势分析的基础。数据库表设计时,record_time字段必不可少。

3. 数据统计与可视化模块这是体现项目价值的“核心”。将枯燥的数据转化为图表。

  • 趋势分析:按日、周、月、年查看各项指标的变化曲线。使用折线图最为合适。
  • 对比分析:比如对比本周和上周的平均步数。可以使用双柱状图。
  • 分布分析:一天中哪个时间段饮水最集中?可以用饼图或热力图。 这个模块强烈建议使用成熟的图表库,如MPAndroidChart。自己从头实现一个绘制流畅、交互丰富的图表成本太高,毕业设计应把精力放在业务逻辑和集成优化上。你需要掌握如何将数据库查询出的List<Entry>数据转换成图表库所需的数据集LineDataSet

4. 提醒与目标管理模块这是赋予应用“灵魂”的部分。

  • 目标设置:允许用户设置短期目标(如“本周每日步数8000以上”)和长期目标(如“三个月减重5公斤”)。
  • 智能提醒:基于目标和历史数据触发提醒。例如,每日晚10点检查若睡眠记录未填写,则推送通知;当连续三天达成运动目标时,推送成就鼓励。
  • 饮水/用药提醒:这是固定的周期性提醒,需要用到AlarmManager或更现代的WorkManager来实现定时任务。这里要注意Android 8.0(API 26)以后的后台执行限制,WorkManager是谷歌推荐的最佳实践。

把这四个模块串起来,就是一个完整的应用逻辑:用户录入数据(模块2),在看板看到汇总(模块1),在统计页分析历史趋势(模块3),并通过设定目标和接收提醒(模块4)来形成健康管理的闭环。你的毕业设计文档,就需要清晰地描绘出这个闭环。

3. 技术架构与核心实现方案选型

确定了做什么,接下来就要解决“怎么做”的问题。技术选型直接决定了开发的难度、应用的性能以及代码的可维护性。对于毕业设计,我推荐一套兼顾成熟度、学习价值和实现效率的技术栈。

3.1 整体技术栈选型

  • 开发语言与框架Kotlin+Jetpack。这已经是Android开发的绝对主流。Kotlin的空安全、扩展函数等特性能让代码更简洁健壮。放弃古老的AsyncTask和裸奔的Activity,拥抱Jetpack组件。
  • 架构模式MVVM(Model-View-ViewModel)。这是谷歌官方推荐的架构。它能很好地将界面逻辑与业务逻辑分离,配合LiveDataStateFlow实现数据驱动UI,让代码结构清晰,也便于单元测试。在文档中,你需要画出清晰的MVVM数据流图。
  • 本地数据库Room Persistence Library。它是SQLite的抽象层,编译时检查SQL语句,大大减少了数据库操作的样板代码和运行时错误。对于健康数据这种结构化、需要持久化存储的需求,Room是不二之选。
  • 图表展示MPAndroidChart。功能强大、文档丰富、社区活跃。它支持几乎所有常见的图表类型,且性能不错。虽然库体积稍大,但对于毕业设计演示的功能丰富性来说,利大于弊。
  • 网络与异步Retrofit+Coroutines(协程)。即使你的应用主打离线,保留网络层也为未来扩展(如数据备份到云端)留有余地。Retrofit处理HTTP请求,协程处理异步操作,代码可读性远超回调地狱。
  • 依赖注入Hilt。它基于Dagger,但简化了大量配置。对于中型项目,引入Hilt可以更好地管理RepositoryViewModel等类的依赖关系,提升代码可测试性。如果你的项目相对简单,也可以暂时不用,但在文档中提及这一点能展示你的技术视野。

3.2 数据库设计:Room实战详解

数据库设计是项目的基石。以最核心的“体重记录”为例,我们来看如何用Room实现。

首先,定义实体类(Entity),也就是数据库表:

@Entity(tableName = "weight_records") data class WeightRecord( @PrimaryKey(autoGenerate = true) val id: Long = 0, val weight: Float, // 体重值,单位公斤 val unit: String = "kg", // 单位 val note: String? = null, // 可选备注 @ColumnInfo(name = "record_time") val recordTime: Long // 记录时间戳,System.currentTimeMillis() )

注意,这里将recordTime定义为Long类型存储时间戳,而不是字符串,便于后续按时间范围查询和排序。

接着,定义数据访问对象(DAO),也就是操作接口:

@Dao interface WeightRecordDao { @Insert suspend fun insert(record: WeightRecord) @Query("DELETE FROM weight_records WHERE id = :id") suspend fun deleteById(id: Long) // 查询某段时间内的所有记录,按时间倒序排列 @Query("SELECT * FROM weight_records WHERE record_time BETWEEN :start AND :end ORDER BY record_time DESC") fun getRecordsBetween(start: Long, end: Long): Flow<List<WeightRecord>> // 查询最新的一条记录 @Query("SELECT * FROM weight_records ORDER BY record_time DESC LIMIT 1") fun getLatestRecord(): Flow<WeightRecord?> }

这里使用了Flow作为返回类型。Flow是协程中的响应式流,当数据库中的数据发生变化时,UI层(如ViewModel)能自动接收到更新并刷新界面,这是实现数据驱动UI的关键。

最后,创建数据库抽象类:

@Database(entities = [WeightRecord::class, /* 其他实体类,如StepRecord, SleepRecord等 */], version = 1, exportSchema = false) abstract class HealthDatabase : RoomDatabase() { abstract fun weightRecordDao(): WeightRecordDao // ... 其他Dao }

Application类中初始化这个数据库的单例实例。

3.3 关键实现:使用WorkManager实现智能饮水提醒

固定时间提醒是健康应用的常见功能。我们以“每日定时提醒喝水”为例,看看如何用WorkManager实现。

首先,定义一个Worker类,它负责执行具体的提醒任务(这里发送一个通知):

class DrinkWaterReminderWorker(context: Context, params: WorkerParameters) : Worker(context, params) { override fun doWork(): Result { // 1. 创建通知渠道(针对Android 8.0+) createNotificationChannel() // 2. 构建通知 val notificationId = 1 val notification = NotificationCompat.Builder(applicationContext, CHANNEL_ID) .setSmallIcon(R.drawable.ic_water_drop) // 一个小水滴图标 .setContentTitle("喝水时间到!") .setContentText("已经有一段时间没喝水了,记得补充水分哦~") .setPriority(NotificationCompat.PRIORITY_DEFAULT) .setAutoCancel(true) .build() // 3. 发送通知 val notificationManager = NotificationManagerCompat.from(applicationContext) notificationManager.notify(notificationId, notification) // 返回成功结果,WorkManager可能会根据返回结果决定是否重试 return Result.success() } private fun createNotificationChannel() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { val channel = NotificationChannel( CHANNEL_ID, "健康提醒", NotificationManager.IMPORTANCE_DEFAULT ).apply { description = "用于接收喝水、运动等健康提醒" } val notificationManager = applicationContext.getSystemService(NotificationManager::class.java) notificationManager.createNotificationChannel(channel) } } companion object { const val CHANNEL_ID = "health_reminder_channel" } }

然后,在用户设置提醒时间(比如上午10点)时,我们安排一个周期性的工作请求:

fun scheduleDailyDrinkReminder(context: Context, hourOfDay: Int, minute: Int) { // 1. 定义重复执行的约束条件(例如,仅在设备充电且联网时执行?这里我们不需要,所以用Constraints.NONE) val constraints = Constraints.Builder() .setRequiresBatteryNotLow(true) // 可选:电量不低时执行 .build() // 2. 计算第一次执行的时间(今天指定的时分) val calendar = Calendar.getInstance().apply { set(Calendar.HOUR_OF_DAY, hourOfDay) set(Calendar.MINUTE, minute) set(Calendar.SECOND, 0) // 如果现在的时间已经过了今天设定的时间,就设定为明天 if (timeInMillis <= System.currentTimeMillis()) { add(Calendar.DAY_OF_YEAR, 1) } } val initialDelay = calendar.timeInMillis - System.currentTimeMillis() // 3. 构建周期性工作请求,间隔24小时 val dailyReminderRequest = PeriodicWorkRequestBuilder<DrinkWaterReminderWorker>(24, TimeUnit.HOURS) .setInitialDelay(initialDelay, TimeUnit.MILLISECONDS) .setConstraints(constraints) .build() // 4. 使用唯一的WorkManager实例,并赋予一个唯一的名字,这样我们可以更新或取消它 WorkManager.getInstance(context).enqueueUniquePeriodicWork( "daily_drink_reminder", ExistingPeriodicWorkPolicy.UPDATE, // 如果已存在同名任务,则更新它 dailyReminderRequest ) }

实操心得WorkManager的一大优势是它由系统调度,能很好地处理应用进程被杀、设备重启等情况。即使你的App被关闭,到了预定时间,系统仍会尝试唤醒并执行你的Worker。这对于提醒类功能至关重要。另外,记得在AndroidManifest.xml中注册你的Worker类。

4. 毕业设计文档的核心结构与撰写要点

一份优秀的毕业设计文档,其重要性不亚于可运行的代码。它是对你整个设计、开发过程的系统性总结和展示。很多同学代码写得不错,但文档东拼西凑,逻辑混乱,非常吃亏。我以导师评审的视角,告诉你一份合格的文档应该包含哪些核心章节,以及每个章节怎么写才能出彩。

4.1 摘要、绪论与需求分析

这是文档的“脸面”,决定了评审老师的第一印象。

  • 摘要:用300-500字高度概括整个项目。必须包含:项目背景与意义(为什么做健康管理App)、项目目标(要做一个什么样的系统)、采用的关键技术(Kotlin、Jetpack、Room等)、最终实现的主要功能以及项目成果(完成了一个具备XX功能的可运行应用)。避免空洞的套话,直接陈述事实。
  • 绪论:可以适当扩展背景,阐述移动健康管理的现状与发展,引用一些权威的行业报告数据来支撑你的选题价值。然后明确指出本论文(设计)的主要研究内容和章节安排。
  • 需求分析:这是展示你系统化思维的关键。不要只写“用户需要记录体重”。
    • 功能性需求:用结构化的方式列出。例如:
      • F1. 用户管理:注册、登录、个人信息维护。
      • F2. 健康数据记录:支持体重、步数、睡眠、饮水的增删改查。
      • F3. 数据可视化:以折线图、柱状图形式展示历史数据趋势。
      • F4. 提醒功能:支持自定义时间的周期性健康提醒。
      • F5. 目标管理:支持设定并追踪健康目标。
    • 非功能性需求
      • 性能:列表滑动流畅,图表渲染无卡顿。
      • 易用性:主要操作在3次点击内完成,界面符合Material Design规范。
      • 可靠性:数据本地持久化,应用崩溃后数据不丢失。
      • 可扩展性:模块化设计,便于后续增加新的健康指标(如心率)。

4.2 系统设计与详细实现

这是文档的“躯干”,比重最大,需要详细展开。

  • 总体设计:画出系统的架构图(展示MVVM各层关系)和功能模块图(展示4大模块及其子功能)。图文并茂,一目了然。
  • 数据库设计:这是技术评审的重点。列出所有实体类(WeightRecord,StepRecord等)的详细字段说明(名称、类型、约束、注释)。最好能提供ER图(实体关系图)。详细阐述你为何这样设计表结构,例如,为什么将记录与用户分开?为什么用时间戳而不是日期字符串?
  • 关键模块详细设计
    • 数据记录模块:画出核心记录流程的时序图,包括用户操作、UI层、ViewModel、Repository、DAO、Database之间的交互。这能极大地体现你的设计能力。
    • 统计图表模块:说明你选择MPAndroidChart的理由,并详细描述数据流转过程:Repository从Room查询List<实体>-> 转换成List<Entry>-> 配置LineDataSetLineData-> 设置给LineChart。可以附上关键转换代码。
    • 提醒模块:对比AlarmManagerWorkManager的优劣,解释你选择后者的原因。画出提醒任务的调度与执行流程图。
  • 界面设计与实现:不要简单截图。应对每个主要界面(如主看板、数据记录页、统计页)进行说明,解释其布局设计(用了哪些ConstraintLayoutRecyclerView等)、交互逻辑,并说明其如何遵循Material Design原则(如色彩、间距、图标)。

4.3 测试、总结与源码结构

这是文档的“收尾”,确保项目完整闭环。

  • 系统测试:不要只写“进行了测试,运行良好”。设计测试用例。
    • 功能测试:以表格形式列出。例如:
      测试用例编号测试功能操作步骤预期结果实际结果是否通过
      TC-01体重记录1.进入体重记录页 2.输入65.5 3.点击保存1.提示保存成功 2.返回主页,看板体重更新为65.5与预期一致
    • 性能测试:记录关键页面的启动时间、列表加载千条数据时的滚动帧率。可以使用Android Studio自带的Profiler工具。
    • 兼容性测试:在API 28(Android 9)和 API 34(Android 14)等不同版本模拟器上运行核心功能。
  • 总结与展望:总结整个项目完成的工作,实现了哪些需求,采用了哪些关键技术。然后真诚地分析项目的不足:例如,UI美观度有待提升、未实现云端同步功能、提醒算法较为简单等。最后,基于这些不足,提出可行的未来改进方向,如引入机器学习模型对睡眠质量进行简单评估、集成第三方健康平台API等。这部分能体现你的批判性思维和持续学习的态度。
  • 源码结构说明:在附录或专门章节,简要说明项目源码的目录结构。例如:
    app/ ├── src/main/ │ ├── java/com/yourpackage/ │ │ ├── data/ # 数据层:Entity, Dao, Database │ │ ├── repository/ # 仓库层,协调本地与远程数据源 │ │ ├── viewmodel/ # ViewModel层,准备UI数据 │ │ └── ui/ # UI层:Activity, Fragment, Adapter │ └── res/ # 资源文件
    让评审老师能快速定位代码。

5. 开发中的常见“坑”与优化技巧

在实际编码过程中,你会遇到很多教程里不会细讲的问题。我总结了几类最常见的“坑”和应对技巧,能帮你节省大量调试时间。

5.1 数据层与UI层的同步问题

问题描述:在FragmentActivity中观察ViewModel里的LiveData,当数据库更新后,UI没有自动刷新。

排查与解决

  1. 检查LiveData的观察者:确保你在onCreateViewonCreate中正确调用了observe方法,并且传入的LifecycleOwner是正确的(通常是viewLifecycleOwner用于Fragment)。
    // 正确示例 (在Fragment中) viewModel.weightRecords.observe(viewLifecycleOwner) { records -> // 更新UI adapter.submitList(records) }
    如果使用this而不是viewLifecycleOwner,在Fragment进入后台又返回时,可能会重复观察或发生内存泄漏。
  2. 检查RepositoryDAO的返回类型:确保你的DAO查询方法返回的是Flow<T>LiveData<T>,而不是普通的List<T>。只有可观察的数据类型,才能在数据变化时通知UI。
    // DAO中 @Query("SELECT * FROM weight_records") fun getAllRecords(): Flow<List<WeightRecord>> // 正确,可观察 // @Query("SELECT * FROM weight_records") // fun getAllRecords(): List<WeightRecord> // 错误,一次性查询
  3. 确认更新操作触发了数据流:当你调用ViewModel中的某个方法(如insertRecord)来插入数据时,确保这个方法最终调用了DAOsuspend插入函数,并且这个操作是在协程中发起的(例如使用viewModelScope.launch)。Room会在事务完成后自动更新关联的Flow

5.2 图表性能与体验优化

问题描述:当历史数据量很大(比如一年的每日体重记录,365条)时,折线图加载缓慢,缩放和滑动卡顿。

优化技巧

  1. 数据采样:对于长时间跨度的展示,没必要把所有原始数据点都塞给图表。可以在Repository层进行数据聚合。例如,当查看“年”趋势时,将数据按“月”聚合,计算每个月的平均值或最后一天的值,再将这12个点传给图表,性能会得到巨大提升。
    // 伪代码:按月聚合体重数据 fun getMonthlyAverageWeight(year: Int): Flow<List<Entry>> { return database.weightRecordDao().getRecordsForYear(year) .map { list -> list.groupBy { record -> // 根据recordTime的时间戳,提取出月份 getMonthFromTimestamp(record.recordTime) }.map { (month, records) -> val avgWeight = records.map { it.weight }.average().toFloat() Entry(month.toFloat(), avgWeight) // 月份作为X轴,平均体重作为Y轴 }.sortedBy { it.x } // 按月份排序 } }
  2. 合理配置图表属性:MPAndroidChart有很多属性可以关闭以提高性能。
    lineChart.apply { setDrawGridBackground(false) // 关闭网格背景绘制 description.isEnabled = false // 关闭描述文字 legend.isEnabled = false // 如果图例不必要,可以关闭 // 关闭双指缩放和拖拽(如果不需要) // isDragEnabled = false // setScaleEnabled(false) // 或者,启用但限制缩放比例,避免过度绘制 setScaleMinima(1f, 1f) setViewPortOffsets(10f, 10f, 10f, 10f) // 设置边距 }
  3. 使用RecyclerView分页加载:如果你的应用设计是图表列表(例如不同健康指标的不同图表),切勿将所有图表的LineData一次性创建。应该使用RecyclerView来承载每个图表项,实现视图复用,仅当图表项进入屏幕时才初始化其数据。

5.3 后台任务与电量优化

问题描述:使用AlarmManager设置了精确的定时提醒,但在部分厂商(如小米、华为)的设备上,应用退到后台后提醒不触发。

解决方案与最佳实践

  1. 拥抱WorkManager:如前所述,WorkManager是处理延迟和周期性后台任务的首选。它兼容性好,能自动适应不同厂商的省电策略。
  2. 设置合理的约束条件:不要无条件地执行后台任务。使用Constraints.Builder来设置条件,例如.setRequiresCharging(true)(仅在充电时执行)、.setRequiredNetworkType(NetworkType.CONNECTED)(仅在联网时执行)。对于喝水提醒,可以设置为.setRequiresBatteryNotLow(true),这样在电量低时系统会推迟任务,避免引起用户反感。
  3. 使用前台服务需谨慎:如果你的应用需要在后台持续运行(例如持续监测心率),可能需要启动前台服务并显示一个持续的通知。但这会显著增加电量消耗,且需要向用户申请FOREGROUND_SERVICE权限,体验并不好。对于健康管家这类记录型应用,应尽量避免。更推荐使用WorkManagerOneTimeWorkRequestPeriodicWorkRequest,在特定时刻唤醒执行任务,然后立即结束。

5.4 应用兼容性与适配

问题描述:应用在Android 10上运行正常,但在Android 13或14上,无法读取步数传感器数据,或者通知不显示。

关键适配点

  1. 运行时权限:从Android 6.0开始,敏感权限需要动态申请。健康应用可能需要的权限包括:
    • ACTIVITY_RECOGNITION:用于识别用户活动(如走路、跑步),获取步数。这是危险权限,必须动态申请。
    • POST_NOTIFICATIONSAndroid 13(API 33)及以上,发送通知需要单独申请此权限。在AndroidManifest.xml中声明后,在需要发送通知前(如用户首次设置提醒时),检查并申请。
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { if (ContextCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) { requestPermissions(arrayOf(Manifest.permission.POST_NOTIFICATIONS), REQUEST_CODE_NOTIFICATION) } }
  2. 存储权限变更:如果你的应用需要导出健康报告为文件,请注意Android 11(API 30)引入了作用域存储。优先使用MediaStore或应用专属目录,避免直接请求READ_EXTERNAL_STORAGEWRITE_EXTERNAL_STORAGE
  3. 后台位置权限:如果你的应用包含基于位置的运动轨迹记录,需要申请ACCESS_BACKGROUND_LOCATION权限,且审核非常严格。毕业设计中如非必要,建议避开此功能。

把这些“坑”提前了解清楚,并在设计和编码时规避,能让你项目的稳定性和成熟度提升一个档次。最后,记得在真机上,尤其是不同Android版本的设备上进行充分测试,模拟器无法完全替代真机环境。

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

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

家庭聚餐火锅推荐试了6家,爸妈说这桌吃得最舒坦

家庭聚餐火锅推荐的核心判断标准是口味兼容度、食材新鲜度与用餐氛围的平衡&#xff0c;走访5个火锅品牌的6家门店后&#xff0c;遇南三的综合表现适配家庭聚餐的需求度较高。 对比维度 核心参考指标 锅底兼容度 是否有鸳鸯锅、辣度是否可调节 食材适配度 是否覆盖老人、小…

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

深度学习人脸姿态估计:从原理到部署的全流程实战指南

简介&#xff1a;本资源是一套面向本科毕业设计与课程设计的深度学习实战项目&#xff0c;聚焦人脸姿态估计这一典型计算机视觉任务&#xff0c;适用于具备Python与PyTorch/TensorFlow基础的学习者开展期末大作业或算法实践。项目基于YOLO架构改进实现人脸关键点检测与三维姿态…

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

PHP版LIMS实战:中小型检测实验室的合规高效落地方案

简介&#xff1a;这是一套面向实验室管理人员、PHP开发者及高校教学实践者的开源LIMS&#xff08;实验室信息管理系统&#xff09;完整实现&#xff0c;聚焦开放实验室场景下的样品管理、任务分配、结果录入、质量控制与报告生成等核心业务流程。资源为ZIP压缩包&#xff0c;共…

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

Java+Uniapp全栈智能商城实战:架构设计、核心模块与性能优化

简介&#xff1a;本资源是一套完整的智能小程序商城系统源码&#xff0c;面向Java后端开发者、uniapp前端学习者及全栈项目实践者&#xff0c;解决多角色电商系统从开发到部署的全流程需求。压缩包共1449个文件&#xff0c;涵盖145个Java后端业务与接口代码、266个Vue页面组件、…

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

高创LDHD2直线电机调试实战:从硬件连接到参数配置与故障排查

简介&#xff1a;本资源面向工业自动化领域的PLC工程师、运动控制调试人员及机电一体化技术人员&#xff0c;聚焦高创LDHD2直线电机驱动器的工程落地应用&#xff0c;解决驱动器选型、通信配置、参数整定与系统联调等核心问题。压缩包共10个文件&#xff0c;涵盖中英文用户手册…

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

Oracle迁移达梦数据库三步法:结构、数据与应用适配指南

国产数据库迁移&#xff0c;尤其是 Oracle 向达梦数据库迁移&#xff0c;很多人第一反应是“工作量巨大、语法不兼容、风险不可控”。实际跑过一轮常规业务库的迁移之后&#xff0c;结论并没有那么复杂&#xff1a;只要把过程强行切分成“结构迁移、数据迁移、应用适配”三个独…

作者头像 李华