鸿蒙跨端计步器:多设备同步步数统计系统 原创

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

鸿蒙跨端计步器:多设备同步步数统计系统

本文将基于HarmonyOS 5的传感器能力和分布式技术,实现一个支持多设备同步的计步器应用,能够在不同设备间同步步数数据并合并统计结果。

技术架构
传感器层:通过加速度传感器检测步伐

算法层:步伐检测算法和步数统计逻辑

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

UI展示层:实时显示步数和同步状态

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

// model/StepData.ts
export class StepData {
userId: string = ‘’; // 用户ID
deviceId: string = ‘’; // 设备ID
date: string = ‘’; // 日期(YYYY-MM-DD)
steps: number = 0; // 步数
lastUpdate: number = 0; // 最后更新时间戳
isSynced: boolean = false; // 是否已同步

constructor(data?: Partial<StepData>) {
if (data) {
Object.assign(this, data);
if (!this.date) {
this.date = this.getCurrentDate();
if (!this.lastUpdate) {

    this.lastUpdate = Date.now();

}

// 获取当前日期字符串

private getCurrentDate(): string {
const date = new Date();
return {date.getFullYear()}-{(date.getMonth() + 1).toString().padStart(2, ‘0’)}-${date.getDate().toString().padStart(2, ‘0’)};
}

计步器服务实现

// service/StepCounterService.ts
import sensor from ‘@ohos.sensor’;
import { StepData } from ‘…/model/StepData’;

const SENSOR_TYPE = sensor.SensorType.SENSOR_TYPE_ACCELEROMETER;
const SENSOR_INTERVAL = 100000; // 100ms
const STEP_THRESHOLD = 12; // 步伐检测阈值

export class StepCounterService {
private sensorId: number = -1;
private lastAcceleration: number[] = [0, 0, 0];
private stepCount: number = 0;
private todayData: StepData = new StepData();
private onStepCallback: (steps: number) => void = () => {};

// 初始化计步器
async initialize(userId: string, callback: (steps: number) => void) {
this.onStepCallback = callback;
this.todayData.userId = userId;

try {
  this.sensorId = await sensor.on(SENSOR_TYPE, {
    interval: SENSOR_INTERVAL,
    success: (data) => this.handleSensorData(data),
    fail: (err) => console.error('传感器启动失败:', err)
  });
  console.info('计步器初始化成功');

catch (err) {

  console.error('计步器初始化失败:', err);

}

// 处理传感器数据
private handleSensorData(sensorData: sensor.SensorResponse) {
const acceleration = [
sensorData.x - this.lastAcceleration[0],
sensorData.y - this.lastAcceleration[1],
sensorData.z - this.lastAcceleration[2]
];

this.lastAcceleration = [sensorData.x, sensorData.y, sensorData.z];

// 计算加速度变化量
const delta = Math.sqrt(
  acceleration[0] * acceleration[0] +
  acceleration[1] * acceleration[1] +
  acceleration[2] * acceleration[2]
);

// 检测步伐
if (delta > STEP_THRESHOLD) {
  this.stepCount++;
  this.todayData.steps = this.stepCount;
  this.todayData.lastUpdate = Date.now();
  this.onStepCallback(this.stepCount);

}

// 获取今日步数
getTodaySteps(): StepData {
return this.todayData;
// 重置步数

resetSteps() {
this.stepCount = 0;
this.todayData.steps = 0;
this.todayData.lastUpdate = Date.now();
this.onStepCallback(0);
// 释放传感器资源

cleanup() {
if (this.sensorId !== -1) {
sensor.off(this.sensorId);
this.sensorId = -1;
}

分布式步数同步服务

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

const STORE_ID = ‘step_sync_store’;
const STEP_KEY_PREFIX = ‘step_data_’;

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

// 初始化分布式数据存储
async initialize() {
const config = {
bundleName: ‘com.example.stepcounter’,
userInfo: {
userId: ‘step_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(STEP_KEY_PREFIX)) {
const stepData: StepData = JSON.parse(entry.value.value);
this.mergeStepData(stepData);
});

}

// 合并步数数据
private mergeStepData(newData: StepData) {
const currentData: Map<string, StepData> = AppStorage.get(‘stepDataMap’) || new Map();
const existingData = currentData.get(newData.date);

if (existingData) {
  // 合并步数(取最大值)
  existingData.steps = Math.max(existingData.steps, newData.steps);
  existingData.lastUpdate = Math.max(existingData.lastUpdate, newData.lastUpdate);
  existingData.isSynced = true;

else {

  newData.isSynced = true;
  currentData.set(newData.date, newData);

AppStorage.setOrCreate(‘stepDataMap’, currentData);

// 同步步数数据

async syncStepData(stepData: StepData) {
stepData.deviceId = this.localDeviceId;
const stepKey = {STEP_KEY_PREFIX}{stepData.date};
await this.kvStore.put(stepKey, JSON.stringify(stepData));
// 获取所有设备的步数数据

async getAllStepData(userId: string): Promise<StepData[]> {
const entries = await this.kvStore.getEntries(STEP_KEY_PREFIX);
return Array.from(entries.values())
.map(entry => new StepData(JSON.parse(entry.value.value)))
.filter(data => data.userId === userId);
}

计步器页面实现

// pages/StepCounterPage.ets
import { StepCounterService } from ‘…/service/StepCounterService’;
import { StepSyncService } from ‘…/service/StepSyncService’;
import { StepData } from ‘…/model/StepData’;

@Entry
@Component
struct StepCounterPage {
private stepService: StepCounterService = new StepCounterService();
private syncService: StepSyncService = new StepSyncService();
@StorageLink(‘stepDataMap’) stepDataMap: Map<string, StepData> = new Map();
@State todaySteps: number = 0;
@State isSyncing: boolean = false;
@State userId: string = ‘default_user’;

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

// 初始化计步器
this.stepService.initialize(this.userId, (steps) => {
  this.todaySteps = steps;
  this.updateTodayStepData(steps);
});

onPageHide() {

this.stepService.cleanup();

build() {

Column() {
  // 步数显示
  Text(this.todaySteps.toString())
    .fontSize(72)
    .fontWeight(FontWeight.Bold)
    .margin({ top: 40, bottom: 20 })
  
  Text('今日步数')
    .fontSize(18)
    .fontColor('#666666')
    .margin({ bottom: 40 })
  
  // 同步状态
  Row() {
    Circle()
      .width(10)
      .height(10)
      .fill(this.isSyncing ? '#FFC107' : 
            this.stepDataMap.get(this.getTodayDate())?.isSynced ? '#4CAF50' : '#F44336')
      .margin({ right: 5 })
    
    Text(this.isSyncing ? '同步中...' : 
         this.stepDataMap.get(this.getTodayDate())?.isSynced ? '已同步' : '未同步')
      .fontSize(14)

.margin({ bottom: 20 })

  // 同步按钮
  Button('同步步数')
    .width(200)
    .onClick(async () => {
      await this.syncTodaySteps();
    })
  
  // 历史记录
  Text('历史记录')
    .fontSize(18)
    .fontWeight(FontWeight.Bold)
    .margin({ top: 40, bottom: 10 })
  
  List() {
    ForEach(Array.from(this.stepDataMap.entries()).reverse(), ([date, data]) => {
      if (date !== this.getTodayDate()) {
        ListItem() {
          StepHistoryItem({ date, data })

}

    })

.layoutWeight(1)

  .width('90%')

.width(‘100%’)

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

// 获取当前日期字符串

private getTodayDate(): string {
const date = new Date();
return {date.getFullYear()}-{(date.getMonth() + 1).toString().padStart(2, ‘0’)}-${date.getDate().toString().padStart(2, ‘0’)};
// 更新今日步数数据

private updateTodayStepData(steps: number) {
const today = this.getTodayDate();
const newData = new StepData({
userId: this.userId,
deviceId: this.syncService.getLocalDeviceId(),
date: today,
steps: steps,
lastUpdate: Date.now()
});

const newMap = new Map(this.stepDataMap);
newMap.set(today, newData);
AppStorage.setOrCreate('stepDataMap', newMap);

// 加载步数数据

private async loadStepData() {
const remoteData = await this.syncService.getAllStepData(this.userId);
const newMap = new Map<string, StepData>();

// 合并远程数据
remoteData.forEach(data => {
  newMap.set(data.date, data);
});

// 添加本地今日数据
const today = this.getTodayDate();
if (!newMap.has(today)) {
  newMap.set(today, new StepData({
    userId: this.userId,
    deviceId: this.syncService.getLocalDeviceId(),
    date: today,
    steps: this.todaySteps
  }));

AppStorage.setOrCreate(‘stepDataMap’, newMap);

// 同步今日步数

private async syncTodaySteps() {
this.isSyncing = true;
const today = this.getTodayDate();
const todayData = this.stepDataMap.get(today);

if (todayData) {
  await this.syncService.syncStepData(todayData);
  todayData.isSynced = true;
  const newMap = new Map(this.stepDataMap);
  newMap.set(today, todayData);
  AppStorage.setOrCreate('stepDataMap', newMap);

this.isSyncing = false;

}

@Component
struct StepHistoryItem {
@Prop date: string;
@Prop data: StepData;

build() {
Row() {
Text(this.date)
.fontSize(16)
.layoutWeight(1)

  Text(this.data.steps.toString())
    .fontSize(16)
    .fontWeight(FontWeight.Bold)
  
  // 同步状态指示器
  Circle()
    .width(8)
    .height(8)
    .fill(this.data.isSynced ? '#4CAF50' : '#F44336')
    .margin({ left: 8 })

.width(‘100%’)

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

}

实现原理详解
步伐检测算法:

使用加速度传感器检测设备运动

计算三轴加速度变化量

当变化量超过阈值时计为一步
数据同步机制:

本地步数变化时更新内存数据

定期或手动触发同步到分布式数据库

其他设备接收更新后合并数据
冲突解决策略:

同一天的步数取最大值

保留最后更新时间戳

显示数据来源设备信息

扩展功能建议
目标设置与达成提醒:

  // 设置步数目标

async setStepGoal(goal: number) {
await this.kvStore.put(‘step_goal’, goal);
this.checkGoalAchievement();

运动轨迹记录:

  // 使用地理位置API记录运动轨迹

async recordMovementTrack() {
const locations = await geoLocation.trackPosition();
await this.syncService.syncMovementTrack(locations);

健康数据整合:

  // 同步到健康应用

async syncToHealthApp() {
const healthData = {
steps: this.todaySteps,
distance: this.calculateDistance(),
calories: this.calculateCalories()
};
await healthKit.saveData(healthData);

总结

本文展示了如何利用HarmonyOS的传感器能力和分布式技术构建一个多设备同步的计步器应用。通过加速度传感器检测步伐,再通过分布式数据管理实现步数数据的跨设备同步,为用户提供了准确的运动数据统计。

这种架构不仅适用于计步器,也可以扩展到心率监测、睡眠跟踪等其他健康应用场景。合理利用鸿蒙的分布式能力,可以打造出真正无缝衔接的全场景健康管理体验。

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