
鸿蒙跨端计步器:多设备同步步数统计系统 原创
鸿蒙跨端计步器:多设备同步步数统计系统
本文将基于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的传感器能力和分布式技术构建一个多设备同步的计步器应用。通过加速度传感器检测步伐,再通过分布式数据管理实现步数数据的跨设备同步,为用户提供了准确的运动数据统计。
这种架构不仅适用于计步器,也可以扩展到心率监测、睡眠跟踪等其他健康应用场景。合理利用鸿蒙的分布式能力,可以打造出真正无缝衔接的全场景健康管理体验。
