鸿蒙跨端健康数据同步:BMI指数计算器与多设备数据共享 原创

进修的泡芙
发布于 2025-6-18 21:03
浏览
0收藏

鸿蒙跨端健康数据同步:BMI指数计算器与多设备数据共享

本文将基于HarmonyOS 5的分布式能力和ArkUI框架,实现一个跨设备的BMI指数计算器,能够在多个设备间同步健康数据,同时展示如何使用条件语句进行健康状态判断。

技术架构
数据计算层:计算BMI指数并评估健康状态

数据同步层:通过分布式数据管理实现多设备数据共享

UI展示层:响应式UI展示计算结果和历史记录

设备管理层:发现和连接同一账号下的其他设备

完整代码实现
健康数据模型定义

// model/HealthData.ts
export class HealthData {
userId: string = ‘’; // 用户ID
deviceId: string = ‘’; // 设备ID
timestamp: number = 0; // 记录时间戳
height: number = 0; // 身高(cm)
weight: number = 0; // 体重(kg)
bmiValue: number = 0; // BMI值
healthStatus: string = ‘’; // 健康状态

constructor(data?: any) {
if (data) {
this.userId = data.userId || ‘’;
this.deviceId = data.deviceId || ‘’;
this.timestamp = data.timestamp || Date.now();
this.height = data.height || 0;
this.weight = data.weight || 0;
this.calculateBMI();
}

// 计算BMI并评估健康状态
calculateBMI() {
if (this.height > 0 && this.weight > 0) {
const heightInM = this.height / 100;
this.bmiValue = parseFloat((this.weight / (heightInM * heightInM)).toFixed(1));
this.evaluateHealthStatus();
}

// 评估健康状态
private evaluateHealthStatus() {
if (this.bmiValue < 18.5) {
this.healthStatus = ‘偏瘦’;
else if (this.bmiValue >= 18.5 && this.bmiValue < 24) {

  this.healthStatus = '正常';

else if (this.bmiValue >= 24 && this.bmiValue < 28) {

  this.healthStatus = '过重';

else {

  this.healthStatus = '肥胖';

}

分布式健康数据同步服务

// service/HealthSyncService.ts
import distributedData from ‘@ohos.data.distributedData’;
import deviceInfo from ‘@ohos.deviceInfo’;
import { HealthData } from ‘…/model/HealthData’;

const STORE_ID = ‘health_data_store’;
const HEALTH_KEY_PREFIX = ‘bmi_record_’;

export class HealthSyncService {
private kvManager: distributedData.KVManager;
private kvStore: distributedData.SingleKVStore;
private localDeviceId: string = deviceInfo.deviceId;

// 初始化分布式数据存储
async initialize() {
const config = {
bundleName: ‘com.example.healthapp’,
userInfo: {
userId: ‘health_user’,
userType: distributedData.UserType.SAME_USER_ID
};

this.kvManager = distributedData.createKVManager(config);
const options = {
  createIfMissing: true,
  encrypt: false,
  backup: false,
  autoSync: true,
  kvStoreType: distributedData.KVStoreType.SINGLE_VERSION
};

this.kvStore = await this.kvManager.getKVStore(STORE_ID, options);

// 订阅数据变更
this.kvStore.on('dataChange', distributedData.SubscribeType.SUBSCRIBE_TYPE_ALL, (data) => {
  this.handleDataChange(data);
});

// 处理数据变更

private handleDataChange(data: distributedData.ChangeNotification) {
if (data.insertEntries.length > 0) {
data.insertEntries.forEach(entry => {
if (entry.key.startsWith(HEALTH_KEY_PREFIX)) {
const recordId = entry.key.substring(HEALTH_KEY_PREFIX.length);
const healthData: HealthData = JSON.parse(entry.value.value);

      // 更新AppStorage中的健康数据
      const currentRecords: Map<string, HealthData> = AppStorage.get('healthRecords') || new Map();
      currentRecords.set(recordId, healthData);
      AppStorage.setOrCreate('healthRecords', currentRecords);

});

}

// 同步健康数据到所有设备
async syncHealthData(data: HealthData) {
const recordKey = {HEALTH_KEY_PREFIX}{data.timestamp};
await this.kvStore.put(recordKey, JSON.stringify(data));
// 获取远程健康数据

async getRemoteHealthData(userId: string): Promise<HealthData[]> {
const entries = await this.kvStore.getEntries(HEALTH_KEY_PREFIX);
const records: HealthData[] = [];

for (let i = 0; i < entries.length; i++) {
  const entry = entries[i];
  const data: HealthData = JSON.parse(entry.value.value);
  if (data.userId === userId) {
    records.push(data);

}

return records.sort((a, b) => b.timestamp - a.timestamp);

}

BMI计算器页面实现

// pages/BmiCalculatorPage.ets
import { HealthData } from ‘…/model/HealthData’;
import { HealthSyncService } from ‘…/service/HealthSyncService’;

@Entry
@Component
struct BmiCalculatorPage {
private syncService: HealthSyncService = new HealthSyncService();
@State height: string = ‘’;
@State weight: string = ‘’;
@State result: HealthData | null = null;
@StorageLink(‘healthRecords’) healthRecords: Map<string, HealthData> = new Map();

async aboutToAppear() {
await this.syncService.initialize();

// 加载历史记录
const userId = AppStorage.get('userId') || 'default_user';
const records = await this.syncService.getRemoteHealthData(userId);
const newRecords = new Map(this.healthRecords);
records.forEach(r => newRecords.set(r.timestamp.toString(), r));
AppStorage.setOrCreate('healthRecords', newRecords);

build() {

Column() {
  // 标题
  Text('BMI计算器')
    .fontSize(24)
    .fontWeight(FontWeight.Bold)
    .margin({ top: 20, bottom: 30 })
  
  // 输入表单
  Column() {
    Row() {
      Text('身高(cm):')
        .width(100)
        .fontSize(18)
      
      TextInput({ text: this.height })
        .width('60%')
        .type(InputType.Number)
        .onChange((value: string) => {
          this.height = value;
        })

.margin({ bottom: 20 })

    Row() {
      Text('体重(kg):')
        .width(100)
        .fontSize(18)
      
      TextInput({ text: this.weight })
        .width('60%')
        .type(InputType.Number)
        .onChange((value: string) => {
          this.weight = value;
        })

}

  .width('90%')
  .padding(20)
  .backgroundColor('#F5F5F5')
  .borderRadius(12)
  
  // 计算按钮
  Button('计算BMI')
    .width('80%')
    .height(50)
    .margin(20)
    .onClick(() => {
      this.calculateBMI();
    })
  
  // 结果显示
  if (this.result) {
    Column() {
      Text(BMI值: ${this.result.bmiValue})
        .fontSize(20)
        .margin({ bottom: 10 })
      
      Text(健康状态: ${this.result.healthStatus})
        .fontSize(20)
        .fontColor(this.getStatusColor(this.result.healthStatus))
      
      // 健康建议
      Text(this.getHealthAdvice(this.result.healthStatus))
        .fontSize(16)
        .margin({ top: 20 })
        .fontColor('#666666')
        .multilineTextAlignment(TextAlign.Center)

.width(‘90%’)

    .padding(20)
    .margin({ top: 20 })
    .backgroundColor('#FFFFFF')
    .borderRadius(12)
    .shadow({ radius: 2, color: '#10000000', offsetX: 0, offsetY: 1 })

// 历史记录按钮

  Button('查看历史记录')
    .width('80%')
    .margin(20)
    .onClick(() => {
      router.pushUrl({ url: 'pages/HealthHistoryPage' });
    })

.width(‘100%’)

.height('100%')
.alignItems(HorizontalAlign.Center)

// 计算BMI

private calculateBMI() {
const height = parseFloat(this.height);
const weight = parseFloat(this.weight);

if (isNaN(height) |isNaN(weight)

height <= 0
| weight <= 0) {
prompt.showToast({ message: ‘请输入有效的身高和体重’, duration: 2000 });
return;
const healthData = new HealthData({

  userId: AppStorage.get('userId') || 'default_user',
  deviceId: this.syncService.getLocalDeviceId(),
  height: height,
  weight: weight
});

this.result = healthData;

// 同步到其他设备
this.syncService.syncHealthData(healthData);

// 获取健康状态对应的颜色

private getStatusColor(status: string): Color {
switch (status) {
case ‘偏瘦’: return Color.Blue;
case ‘正常’: return Color.Green;
case ‘过重’: return Color.Orange;
case ‘肥胖’: return Color.Red;
default: return Color.Black;
}

// 获取健康建议
private getHealthAdvice(status: string): string {
switch (status) {
case ‘偏瘦’: return ‘建议增加营养摄入,适当进行力量训练以增加肌肉质量’;
case ‘正常’: return ‘保持良好饮食习惯和规律运动,维持当前健康状态’;
case ‘过重’: return ‘建议控制饮食热量,增加有氧运动,每周至少150分钟中等强度运动’;
case ‘肥胖’: return ‘建议咨询营养师制定饮食计划,逐步增加运动量,定期体检’;
default: return ‘’;
}

健康历史记录页面

// pages/HealthHistoryPage.ets
@Entry
@Component
struct HealthHistoryPage {
@StorageLink(‘healthRecords’) healthRecords: Map<string, HealthData> = new Map();

build() {
Column() {
// 标题栏
Row() {
Button(‘返回’)
.onClick(() => {
router.back();
})

    Text('健康历史记录')
      .fontSize(20)
      .fontWeight(FontWeight.Bold)
      .layoutWeight(1)
      .textAlign(TextAlign.Center)

.width(‘100%’)

  .padding(12)
  
  // 历史记录列表
  if (this.healthRecords.size > 0) {
    List() {
      ForEach(Array.from(this.healthRecords.values()), (record: HealthData) => {
        ListItem() {
          HealthRecordItem({ record: record })

})

.layoutWeight(1)

    .width('100%')

else {

    Column() {
      Image($r('app.media.ic_empty'))
        .width(100)
        .height(100)
        .margin({ bottom: 20 })
      
      Text('暂无历史记录')
        .fontSize(18)
        .fontColor('#888888')

.width(‘100%’)

    .height('50%')
    .justifyContent(FlexAlign.Center)

}

.width('100%')
.height('100%')

}

@Component
struct HealthRecordItem {
@Prop record: HealthData

build() {
Column() {
Row() {
Text(this.formatDate(this.record.timestamp))
.fontSize(16)
.fontColor(‘#333333’)
.layoutWeight(1)

    Text(BMI: ${this.record.bmiValue})
      .fontSize(16)
      .fontColor(this.getStatusColor(this.record.healthStatus))

Row() {

    Text(身高: ${this.record.height}cm)
      .fontSize(14)
      .fontColor('#666666')
      .margin({ right: 20 })
    
    Text(体重: ${this.record.weight}kg)
      .fontSize(14)
      .fontColor('#666666')

.margin({ top: 8, bottom: 8 })

  Row() {
    Text('健康状态:')
      .fontSize(14)
      .fontColor('#666666')
    
    Text(this.record.healthStatus)
      .fontSize(14)
      .fontColor(this.getStatusColor(this.record.healthStatus))
      .margin({ left: 8 })

}

.width('100%')
.padding(16)
.backgroundColor('#FFFFFF')
.borderRadius(8)
.margin({ bottom: 8 })

// 格式化日期

private formatDate(timestamp: number): string {
const date = new Date(timestamp);
return {date.getFullYear()}-{(date.getMonth() + 1).toString().padStart(2, ‘0’)}-{date.getDate().toString().padStart(2, ‘0’)} {date.getHours().toString().padStart(2, ‘0’)}:${date.getMinutes().toString().padStart(2, ‘0’)};
// 获取健康状态对应的颜色

private getStatusColor(status: string): Color {
switch (status) {
case ‘偏瘦’: return Color.Blue;
case ‘正常’: return Color.Green;
case ‘过重’: return Color.Orange;
case ‘肥胖’: return Color.Red;
default: return Color.Black;
}

实现原理详解
BMI计算逻辑:

BMI = 体重(kg) / (身高(m) × 身高(m))

根据计算结果判断健康状态:

BMI < 18.5:偏瘦

18.5 ≤ BMI < 24:正常

24 ≤ BMI < 28:过重

BMI ≥ 28:肥胖
数据同步机制:

使用分布式KVStore存储健康记录

每条记录以时间戳为唯一标识

通过dataChange事件监听远程数据变更
多设备协同流程:

设备A计算BMI并同步到分布式数据库

设备B收到数据变更通知后更新本地UI

所有设备保持健康记录一致

扩展功能建议
健康趋势图表:

  // 使用图表库展示BMI变化趋势

import charts from ‘@ohos.charts’;

function renderTrendChart(records: HealthData[]) {
const chartData = records.map(r => ({
date: r.timestamp,
value: r.bmiValue
}));
// 渲染折线图…

健康目标设置:

  // 设置体重目标并跟踪进度

async setWeightGoal(targetWeight: number) {
await this.kvStore.put(‘weight_goal’, targetWeight);

健康数据导出:

  // 将健康记录导出为CSV文件

async exportToCSV() {
const csvContent = Array.from(this.healthRecords.values())
.map(r => {r.timestamp},{r.height},{r.weight},{r.bmiValue},${r.healthStatus})
.join(‘\n’);
await fileIO.writeText(‘health_records.csv’, csvContent);

总结

本文展示了如何利用HarmonyOS的分布式能力实现跨设备的BMI计算器。通过条件语句实现健康状态判断,再通过分布式数据服务实现健康记录的多设备同步。这种架构不仅适用于健康应用,也可以扩展到健身记录、饮食追踪等场景。

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
收藏
回复
举报
回复
    相关推荐