Flutter for OpenHarmony现代智慧养老App实战:睡眠监测实现
上周,奶奶跟我抱怨说:"最近总是睡不好,半夜醒来好几次,也不知道自己到底睡了多久。"听到这话,我意识到很多老年人都有睡眠问题,但他们往往不知道如何科学地记录和分析自己的睡眠状况。于是,我决定为他们开发一个简单实用的睡眠监测功能。在与多位老年用户交流后,我发现他们最需要的不是复杂的睡眠分期图表,而是,以及。基于这些真实需求,我们设计了这套睡眠监测系统。

上周,奶奶跟我抱怨说:"最近总是睡不好,半夜醒来好几次,也不知道自己到底睡了多久。"听到这话,我意识到很多老年人都有睡眠问题,但他们往往不知道如何科学地记录和分析自己的睡眠状况。于是,我决定为他们开发一个简单实用的睡眠监测功能。
在与多位老年用户交流后,我发现他们最需要的不是复杂的睡眠分期图表,而是能看懂的睡眠时长、简单的睡眠质量评价,以及实用的改善建议。基于这些真实需求,我们设计了这套睡眠监测系统。
睡眠数据模型设计
在设计睡眠数据模型时,我参考了国际睡眠医学会的标准,同时结合老年人的实际使用场景,确定了核心的数据结构。
首先定义睡眠记录的基础模型:
class SleepRecord {
final String id;
final DateTime bedTime;
final DateTime wakeTime;
final int duration;
final int deepSleepDuration;
final int lightSleepDuration;
final int awakeCount;
final String quality;
final String? note;
SleepRecord({
required this.id,
required this.bedTime,
required this.wakeTime,
required this.duration,
required this.deepSleepDuration,
required this.lightSleepDuration,
required this.awakeCount,
required this.quality,
this.note,
});
double get sleepEfficiency {
final totalTime = wakeTime.difference(bedTime).inMinutes;
return (duration / totalTime * 100).clamp(0, 100);
}
}
这个模型涵盖了睡眠监测的核心数据。bedTime 和 wakeTime 记录睡眠的起止时间,duration 存储实际睡眠时长,awakeCount 记录夜间醒来次数。sleepEfficiency 方法自动计算睡眠效率,这是评估睡眠质量的重要指标。
💤 数据设计的实用性考虑:我们没有采用复杂的睡眠分期(REM、NREM等),而是简化为深度睡眠和浅度睡眠两种,这样老年用户更容易理解。睡眠效率的计算公式参考了医学标准,但用百分比表示,更加直观。
创建睡眠统计模型:
class SleepStatistics {
final double averageDuration;
final double averageEfficiency;
final int totalRecords;
final String trend;
SleepStatistics({
required this.averageDuration,
required this.averageEfficiency,
required this.totalRecords,
required this.trend,
});
String get qualityDescription {
if (averageDuration >= 420 && averageEfficiency >= 85) {
return '睡眠质量优秀';
} else if (averageDuration >= 360 && averageEfficiency >= 75) {
return '睡眠质量良好';
} else if (averageDuration >= 300) {
return '睡眠质量一般';
} else {
return '睡眠质量较差';
}
}
}
统计模型用于展示一段时间内的睡眠情况。平均睡眠时长和平均睡眠效率是两个关键指标,趋势分析帮助用户了解睡眠状况的变化。
📊 统计数据的人性化表达:我们参考了《中国成人失眠诊断与治疗指南》,将7小时(420分钟)作为优秀睡眠的标准。但考虑到老年人的实际情况,6小时(360分钟)也被认为是良好的。
睡眠监测控制器
创建核心控制器:
class SleepController extends GetxController {
final RxList<SleepRecord> records = <SleepRecord>[].obs;
final Rx<SleepStatistics?> statistics = Rx<SleepStatistics?>(null);
final RxBool isLoading = false.obs;
void onInit() {
super.onInit();
loadSleepData();
}
Future<void> loadSleepData() async {
isLoading.value = true;
final storedRecords = await SleepStorage.loadRecords();
records.value = storedRecords;
if (records.isEmpty) await _createSampleData();
_calculateStatistics();
isLoading.value = false;
}
}
控制器负责管理所有睡眠数据。首次使用时提供示例数据,帮助用户快速理解功能。
⚡ 数据初始化考虑:示例数据使用真实睡眠场景,让老年用户更容易理解。
实现添加睡眠记录:
void addSleepRecord({
required DateTime bedTime,
required DateTime wakeTime,
int? awakeCount,
String? note,
}) {
final totalMinutes = wakeTime.difference(bedTime).inMinutes;
final quality = _evaluateSleepQuality(totalMinutes, awakeCount ?? 0);
final record = SleepRecord(
id: DateTime.now().millisecondsSinceEpoch.toString(),
bedTime: bedTime,
wakeTime: wakeTime,
duration: totalMinutes,
deepSleepDuration: (totalMinutes * 0.4).round(),
lightSleepDuration: (totalMinutes * 0.6).round(),
awakeCount: awakeCount ?? 0,
quality: quality,
note: note,
);
records.insert(0, record);
SleepStorage.saveRecords(records);
Get.snackbar('记录成功', '睡眠质量:$quality');
}
String _evaluateSleepQuality(int duration, int awakeCount) {
if (duration >= 420 && awakeCount <= 1) return '优秀';
if (duration >= 360 && awakeCount <= 2) return '良好';
if (duration >= 300 && awakeCount <= 3) return '一般';
return '较差';
}
系统自动计算睡眠时长和评估质量。深度睡眠占40%,这是简化算法,但对日常监测足够。
🎯 算法实用性权衡:采用简单规则判断,结果可解释性强,老年用户能理解评价依据。
实现统计计算:
void _calculateStatistics() {
if (records.isEmpty) return;
final recentRecords = records.take(7).toList();
final avgDuration = recentRecords
.map((r) => r.duration)
.reduce((a, b) => a + b) / recentRecords.length;
final trend = _analyzeTrend(recentRecords);
statistics.value = SleepStatistics(
averageDuration: avgDuration,
averageEfficiency: 85.0,
totalRecords: recentRecords.length,
trend: trend,
);
}
String _analyzeTrend(List<SleepRecord> records) {
if (records.length < 3) return '数据不足';
final mid = records.length ~/ 2;
final firstAvg = records.sublist(0, mid)
.map((r) => r.duration)
.reduce((a, b) => a + b) / mid;
final secondAvg = records.sublist(mid)
.map((r) => r.duration)
.reduce((a, b) => a + b) / (records.length - mid);
final diff = secondAvg - firstAvg;
if (diff > 30) return '改善中';
if (diff < -30) return '下降';
return '稳定';
}
统计计算分析最近7天的睡眠数据。趋势分析比较前后半段平均值,30分钟为阈值。
📈 简化处理:用简单前后对比代替复杂时间序列分析,既能反映变化又不过于敏感。
用户界面设计
创建睡眠监测主界面:
class SleepView extends GetView<SleepController> {
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Color(0xFFF5F7FA),
appBar: AppBar(
title: Text('睡眠监测', style: TextStyle(fontSize: 22.sp)),
backgroundColor: Color(0xFF6B5CE7),
actions: [
IconButton(
icon: Icon(Icons.add_circle, size: 32.sp),
onPressed: _showAddDialog,
),
],
),
body: RefreshIndicator(
onRefresh: controller.loadSleepData,
child: _buildBody(),
),
);
}
}
主界面使用紫色主题,因为紫色在色彩心理学中代表宁静和放松,与睡眠主题契合。
🎨 色彩选择的心理学考虑:我们选择紫色而不是蓝色,是因为紫色更柔和,不会像蓝色那样刺激。
实现睡眠统计卡片:
Widget _buildStatisticsCard() {
return Obx(() {
final stats = controller.statistics.value;
if (stats == null) return SizedBox.shrink();
return Container(
margin: EdgeInsets.all(16.w),
padding: EdgeInsets.all(20.w),
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [Color(0xFF6B5CE7), Color(0xFF8B7CE8)],
),
borderRadius: BorderRadius.circular(16.r),
),
child: Column(
children: [
Row(
children: [
Icon(Icons.bedtime, color: Colors.white, size: 28.sp),
SizedBox(width: 12.w),
Text('睡眠概况', style: TextStyle(
fontSize: 20.sp,
color: Colors.white,
fontWeight: FontWeight.bold,
)),
],
),
SizedBox(height: 20.h),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
_buildStatItem(
'平均时长',
'${(stats.averageDuration / 60).toStringAsFixed(1)}小时',
Icons.access_time,
),
_buildStatItem(
'睡眠效率',
'${stats.averageEfficiency.toStringAsFixed(0)}%',
Icons.trending_up,
),
_buildStatItem(
'趋势',
stats.trend,
Icons.show_chart,
),
],
),
],
),
);
});
}
统计卡片用渐变紫色背景营造舒适的视觉效果。三个关键指标并排显示,让用户一眼就能看到睡眠状况。
📊 数据展示的简化原则:我们只展示最重要的三个指标,避免信息过载。每个指标都配有图标,即使不识字也能大概理解含义。
设计睡眠记录卡片:
Widget _buildRecordCard(SleepRecord record) {
final qualityColor = _getQualityColor(record.quality);
return Card(
margin: EdgeInsets.symmetric(horizontal: 16.w, vertical: 8.h),
child: Padding(
padding: EdgeInsets.all(16.w),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Container(
padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 6.h),
decoration: BoxDecoration(
color: qualityColor.withOpacity(0.1),
borderRadius: BorderRadius.circular(12.r),
),
child: Text(record.quality, style: TextStyle(
color: qualityColor,
fontWeight: FontWeight.bold,
)),
),
Spacer(),
Text(_formatDate(record.bedTime), style: TextStyle(
fontSize: 14.sp,
color: Colors.grey[600],
)),
],
),
SizedBox(height: 12.h),
Row(
children: [
Icon(Icons.bedtime, size: 20.sp, color: Colors.grey[600]),
SizedBox(width: 8.w),
Text('${_formatTime(record.bedTime)} - ${_formatTime(record.wakeTime)}',
style: TextStyle(fontSize: 16.sp)),
],
),
SizedBox(height: 8.h),
Row(
children: [
_buildInfoChip('睡眠 ${(record.duration / 60).toStringAsFixed(1)}小时'),
SizedBox(width: 8.w),
_buildInfoChip('醒来 ${record.awakeCount}次'),
],
),
if (record.note != null)
Padding(
padding: EdgeInsets.only(top: 8.h),
child: Text(record.note!, style: TextStyle(
fontSize: 14.sp,
color: Colors.grey[600],
fontStyle: FontStyle.italic,
)),
),
],
),
),
);
}
每条睡眠记录用卡片展示,睡眠质量用醒目的颜色标签显示。时间范围用横杠连接,清晰表达睡眠的起止时间。
🎨 信息层次的视觉设计:最重要的睡眠质量放在最上方,用彩色标签突出。时间信息用图标辅助,数据信息用芯片样式展示,形成清晰的视觉层次。
添加睡眠记录功能
实现添加记录对话框:
void _showAddDialog() {
DateTime? selectedBedTime;
DateTime? selectedWakeTime;
int awakeCount = 0;
final noteController = TextEditingController();
Get.dialog(
AlertDialog(
title: Text('记录睡眠'),
content: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
ListTile(
leading: Icon(Icons.bedtime),
title: Text('上床时间'),
subtitle: Text(selectedBedTime == null
? '点击选择'
: _formatDateTime(selectedBedTime!)),
onTap: () async {
final time = await _selectDateTime(Get.context!);
if (time != null) selectedBedTime = time;
},
),
ListTile(
leading: Icon(Icons.wb_sunny),
title: Text('起床时间'),
subtitle: Text(selectedWakeTime == null
? '点击选择'
: _formatDateTime(selectedWakeTime!)),
onTap: () async {
final time = await _selectDateTime(Get.context!);
if (time != null) selectedWakeTime = time;
},
),
TextField(
decoration: InputDecoration(
labelText: '夜间醒来次数',
hintText: '输入数字',
),
keyboardType: TextInputType.number,
onChanged: (value) => awakeCount = int.tryParse(value) ?? 0,
),
SizedBox(height: 16.h),
TextField(
controller: noteController,
decoration: InputDecoration(
labelText: '备注(可选)',
hintText: '如:睡前喝了牛奶',
),
maxLines: 2,
),
],
),
),
actions: [
TextButton(
onPressed: () => Get.back(),
child: Text('取消'),
),
ElevatedButton(
onPressed: () {
if (selectedBedTime != null && selectedWakeTime != null) {
controller.addSleepRecord(
bedTime: selectedBedTime!,
wakeTime: selectedWakeTime!,
awakeCount: awakeCount,
note: noteController.text.isEmpty ? null : noteController.text,
);
Get.back();
} else {
Get.snackbar('提示', '请选择上床和起床时间');
}
},
child: Text('保存'),
),
],
),
);
}
添加对话框使用列表项选择时间,比直接弹出时间选择器更友好。醒来次数用数字输入,备注提供了示例文字引导用户。
📝 输入方式的适老化设计:我们用点击列表项的方式选择时间,而不是复杂的滚轮选择器。这样老年用户更容易操作,不会因为手抖而选错时间。
睡眠建议功能
实现个性化睡眠建议:
List<String> generateSleepAdvice(SleepRecord record) {
final advice = <String>[];
if (record.duration < 360) {
advice.add('睡眠时间不足6小时,建议提前30分钟上床');
}
if (record.awakeCount > 2) {
advice.add('夜间醒来${record.awakeCount}次,睡前避免喝太多水');
}
if (record.sleepEfficiency < 75) {
advice.add('睡眠效率较低,建议睡前1小时不看手机');
}
if (advice.isEmpty) {
advice.add('睡眠质量很好,继续保持规律作息');
}
return advice;
}
建议系统根据实际睡眠数据生成。睡眠时间不足建议提前上床,频繁醒来建议控制水分摄入,效率低建议减少电子设备使用。
💡 建议的实用性:所有建议都是老年人容易执行的,比如"提前30分钟上床"比"调整生物钟"更具体可行。
数据存储实现
class SleepStorage {
static const String _key = 'sleep_records';
static Future<void> saveRecords(List<SleepRecord> records) async {
final prefs = await SharedPreferences.getInstance();
final jsonList = records.map((r) => r.toJson()).toList();
await prefs.setString(_key, json.encode(jsonList));
}
static Future<List<SleepRecord>> loadRecords() async {
final prefs = await SharedPreferences.getInstance();
final jsonString = prefs.getString(_key);
if (jsonString == null) return [];
final jsonList = json.decode(jsonString) as List;
return jsonList.map((json) => SleepRecord.fromJson(json)).toList();
}
}
使用本地存储保存睡眠数据,确保数据安全。即使应用关闭,用户的睡眠记录也不会丢失。
� 数据安全的重要性:睡眠数据是用户的隐私信息,我们采用本地存储而不是云端,保护用户隐私。
实际应用反馈
在社区试点使用后,我们收到了很多正面反馈。一位68岁的用户说:"现在每天早上起来就记录睡眠,看到’良好’两个字心里就踏实了。"另一位用户反馈:“发现自己睡前喝水太多,改掉这个习惯后,半夜醒来的次数明显减少了。”
这些反馈让我们认识到,简单的记录和反馈就能帮助老年用户改善睡眠质量。不需要复杂的算法,只需要让他们看到变化、得到鼓励。
通过这个睡眠监测功能的开发,我深刻体会到适老化设计的核心:不是功能越多越好,而是把最需要的功能做到极致简单。
核心设计原则总结:
- 简化数据模型:只记录最关键的睡眠指标
- 直观的质量评价:用文字而不是数字表达睡眠质量
- 实用的改善建议:提供具体可执行的生活指导
- 温暖的视觉设计:用柔和的颜色营造舒适感
- 本地数据存储:保护用户隐私安全
这个睡眠监测模块已经帮助了数百位老年用户改善睡眠质量。未来我们还将加入睡眠提醒、睡眠音乐等功能,让老年人睡得更好。
欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net
更多推荐

所有评论(0)