
前言
运动数据同步是确保用户数据安全和多设备访问的核心功能。通过云端同步,用户可以在更换设备后恢复数据,也可以在多个设备上查看同一份运动记录。本文将详细介绍如何在Flutter与OpenHarmony平台上实现可靠的运动数据同步组件,包括增量同步、冲突处理、离线支持、同步状态管理等功能模块的完整实现方案。
Flutter同步数据模型
dart
class SyncRecord {
final String id;
final String type;
final Map<String, dynamic> data;
final DateTime modifiedAt;
final bool isSynced;
final int version;
SyncRecord({
required this.id,
required this.type,
required this.data,
required this.modifiedAt,
this.isSynced = false,
this.version = 1,
});
Map<String, dynamic> toJson() => {
'id': id,
'type': type,
'data': data,
'modifiedAt': modifiedAt.toIso8601String(),
'version': version,
};
}
class SyncStatus {
final DateTime? lastSyncTime;
final int pendingCount;
final bool isSyncing;
final String? error;
SyncStatus({this.lastSyncTime, this.pendingCount = 0, this.isSyncing = false, this.error});
String get statusText {
if (isSyncing) return '同步中...';
if (error != null) return '同步失败';
if (pendingCount > 0) return '待同步 $pendingCount 条';
if (lastSyncTime != null) return '已同步';
return '未同步';
}
}
同步数据模型定义了可同步记录的结构。每条记录包含唯一ID、类型、数据内容、修改时间、同步状态和版本号。version用于冲突检测,当服务器版本高于本地版本时需要处理冲突。SyncStatus封装同步状态信息,包括最后同步时间、待同步数量、是否正在同步和错误信息。statusText属性根据状态返回用户友好的文字描述。
OpenHarmony网络同步服务
typescript
import http from '@ohos.net.http';
class CloudSyncService {
private baseUrl: string = 'https://api.fitness.com/sync';
async uploadRecords(records: Array<object>, userId: string): Promise<object> {
let httpRequest = http.createHttp();
try {
let response = await httpRequest.request(
`${this.baseUrl}/upload`,
{
method: http.RequestMethod.POST,
header: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${userId}`,
},
extraData: JSON.stringify({ records: records }),
}
);
if (response.responseCode === 200) {
return JSON.parse(response.result as string);
}
throw new Error('上传失败');
} finally {
httpRequest.destroy();
}
}
async downloadRecords(userId: string, lastSyncTime: string): Promise<Array<object>> {
let httpRequest = http.createHttp();
try {
let response = await httpRequest.request(
`${this.baseUrl}/download?since=${lastSyncTime}`,
{
method: http.RequestMethod.GET,
header: { 'Authorization': `Bearer ${userId}` },
}
);
if (response.responseCode === 200) {
let result = JSON.parse(response.result as string);
return result['records'] || [];
}
return [];
} finally {
httpRequest.destroy();
}
}
async getServerVersion(recordId: string): Promise<number> {
// 获取服务器端记录版本
return 0;
}
}
网络同步服务处理与云端的数据交互。uploadRecords方法批量上传本地记录到服务器,使用POST请求发送JSON数据。downloadRecords方法从服务器下载指定时间之后修改的记录,实现增量同步。lastSyncTime参数确保只下载新数据,减少传输量。Authorization头携带用户身份信息。这种设计支持双向同步,本地修改上传到云端,云端修改下载到本地。
Flutter同步管理器
dart
class SyncManager extends ChangeNotifier {
SyncStatus _status = SyncStatus();
List<SyncRecord> _pendingRecords = [];
DateTime? _lastSyncTime;
SyncStatus get status => _status;
Future<void> addPendingRecord(SyncRecord record) async {
_pendingRecords.add(record);
_status = SyncStatus(
lastSyncTime: _lastSyncTime,
pendingCount: _pendingRecords.length,
);
notifyListeners();
}
Future<void> sync() async {
if (_status.isSyncing) return;
_status = SyncStatus(
lastSyncTime: _lastSyncTime,
pendingCount: _pendingRecords.length,
isSyncing: true,
);
notifyListeners();
try {
// 上传本地修改
if (_pendingRecords.isNotEmpty) {
await _uploadPendingRecords();
}
// 下载服务器修改
await _downloadServerChanges();
_lastSyncTime = DateTime.now();
_status = SyncStatus(lastSyncTime: _lastSyncTime, pendingCount: 0);
} catch (e) {
_status = SyncStatus(
lastSyncTime: _lastSyncTime,
pendingCount: _pendingRecords.length,
error: e.toString(),
);
}
notifyListeners();
}
Future<void> _uploadPendingRecords() async {
// 上传待同步记录
}
Future<void> _downloadServerChanges() async {
// 下载服务器变更
}
}
同步管理器协调整个同步流程。addPendingRecord方法将新修改的记录加入待同步队列。sync方法执行完整的同步流程:先上传本地修改,再下载服务器变更。使用isSyncing标志防止重复同步。同步过程中更新状态并通知监听者,UI可以显示同步进度。异常处理确保同步失败时记录错误信息,用户可以稍后重试。
Flutter同步状态组件
dart
class SyncStatusWidget extends StatelessWidget {
final SyncStatus status;
final VoidCallback onSync;
const SyncStatusWidget({Key? key, required this.status, required this.onSync}) : super(key: key);
@override
Widget build(BuildContext context) {
return ListTile(
leading: Icon(
status.isSyncing ? Icons.sync : (status.error != null ? Icons.sync_problem : Icons.cloud_done),
color: status.error != null ? Colors.red : Colors.green,
),
title: Text(status.statusText),
subtitle: status.lastSyncTime != null
? Text('上次同步: ${_formatTime(status.lastSyncTime!)}')
: null,
trailing: status.isSyncing
? SizedBox(width: 24, height: 24, child: CircularProgressIndicator(strokeWidth: 2))
: IconButton(icon: Icon(Icons.refresh), onPressed: onSync),
);
}
String _formatTime(DateTime time) {
return '${time.month}/${time.day} ${time.hour}:${time.minute.toString().padLeft(2, '0')}';
}
}
同步状态组件显示当前的同步状态。图标根据状态变化:同步中显示旋转图标,失败显示警告图标,成功显示云完成图标。显示状态文字和上次同步时间。右侧按钮触发手动同步,同步中时显示进度指示器。这种组件让用户随时了解数据同步情况,并可以手动触发同步。
OpenHarmony离线队列服务
typescript
import dataPreferences from '@ohos.data.preferences';
class OfflineQueueService {
private preferences: dataPreferences.Preferences | null = null;
async initialize(context: Context): Promise<void> {
this.preferences = await dataPreferences.getPreferences(context, 'sync_queue');
}
async addToQueue(record: object): Promise<void> {
if (this.preferences) {
let queueJson = await this.preferences.get('queue', '[]') as string;
let queue: Array<object> = JSON.parse(queueJson);
queue.push(record);
await this.preferences.put('queue', JSON.stringify(queue));
await this.preferences.flush();
}
}
async getQueue(): Promise<Array<object>> {
if (this.preferences) {
let queueJson = await this.preferences.get('queue', '[]') as string;
return JSON.parse(queueJson);
}
return [];
}
async clearQueue(): Promise<void> {
if (this.preferences) {
await this.preferences.put('queue', '[]');
await this.preferences.flush();
}
}
async removeFromQueue(recordId: string): Promise<void> {
if (this.preferences) {
let queue = await this.getQueue();
queue = queue.filter((r: object) => r['id'] !== recordId);
await this.preferences.put('queue', JSON.stringify(queue));
await this.preferences.flush();
}
}
}
离线队列服务在网络不可用时缓存待同步数据。addToQueue方法将记录加入队列,getQueue方法获取所有待同步记录。网络恢复后,同步管理器从队列中取出记录进行上传,成功后调用removeFromQueue移除。clearQueue方法在全部同步成功后清空队列。这种离线支持确保用户在没有网络时也能正常使用应用,数据不会丢失。
Flutter冲突解决组件
dart
class ConflictResolutionDialog extends StatelessWidget {
final SyncRecord localRecord;
final SyncRecord serverRecord;
final Function(SyncRecord) onResolved;
const ConflictResolutionDialog({
Key? key,
required this.localRecord,
required this.serverRecord,
required this.onResolved,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return AlertDialog(
title: Text('数据冲突'),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text('该记录在本地和服务器都有修改,请选择保留哪个版本:'),
SizedBox(height: 16),
_buildVersionCard('本地版本', localRecord.modifiedAt, () => onResolved(localRecord)),
SizedBox(height: 8),
_buildVersionCard('服务器版本', serverRecord.modifiedAt, () => onResolved(serverRecord)),
],
),
);
}
Widget _buildVersionCard(String title, DateTime time, VoidCallback onSelect) {
return Card(
child: ListTile(
title: Text(title),
subtitle: Text('修改时间: ${time.toString().substring(0, 19)}'),
trailing: ElevatedButton(onPressed: onSelect, child: Text('选择')),
),
);
}
}
冲突解决组件在检测到数据冲突时让用户选择保留哪个版本。显示本地版本和服务器版本的修改时间,用户可以根据时间判断哪个是最新的修改。选择后调用onResolved回调,同步管理器使用选中的版本覆盖另一个。这种手动冲突解决方式确保用户不会意外丢失重要数据。
Flutter自动同步设置
dart
class AutoSyncSettings extends StatefulWidget {
final bool autoSyncEnabled;
final bool wifiOnly;
final Function(bool, bool) onSettingsChanged;
const AutoSyncSettings({
Key? key,
required this.autoSyncEnabled,
required this.wifiOnly,
required this.onSettingsChanged,
}) : super(key: key);
@override
State<AutoSyncSettings> createState() => _AutoSyncSettingsState();
}
class _AutoSyncSettingsState extends State<AutoSyncSettings> {
late bool _autoSync;
late bool _wifiOnly;
@override
void initState() {
super.initState();
_autoSync = widget.autoSyncEnabled;
_wifiOnly = widget.wifiOnly;
}
@override
Widget build(BuildContext context) {
return Column(
children: [
SwitchListTile(
title: Text('自动同步'),
subtitle: Text('运动结束后自动同步数据'),
value: _autoSync,
onChanged: (value) {
setState(() => _autoSync = value);
widget.onSettingsChanged(_autoSync, _wifiOnly);
},
),
SwitchListTile(
title: Text('仅WiFi同步'),
subtitle: Text('仅在WiFi网络下自动同步'),
value: _wifiOnly,
onChanged: _autoSync ? (value) {
setState(() => _wifiOnly = value);
widget.onSettingsChanged(_autoSync, _wifiOnly);
} : null,
),
],
);
}
}
自动同步设置让用户配置同步行为。自动同步开关控制是否在运动结束后自动上传数据。仅WiFi同步选项避免消耗移动数据流量,只有自动同步开启时才可用。这种设置给用户足够的控制权,满足不同用户的需求。
总结
本文全面介绍了Flutter与OpenHarmony平台上运动数据同步组件的实现方案。从数据模型到网络服务,从同步管理到离线支持,从冲突处理到自动同步,涵盖了数据同步功能的各个方面。通过可靠的同步机制,我们可以确保用户的运动数据安全,支持多设备访问,提升用户体验。
欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net