OpenHarmony 与 Flutter 的完美融合财务管理应用:数据同步工具
OpenHarmony 钱包应用 v1.11.0 版本新增完整数据同步功能,支持交易、预算和标签等数据的云端同步。该版本实现了多设备数据同步能力,包含核心同步模型定义、数据同步服务管理和可视化同步状态界面。同步服务采用队列管理机制,提供同步统计、历史记录等功能,并通过进度条直观展示同步状态。新功能采用青色渐变UI设计,确保与现有界面风格协调统一。
·
更新概述
v1.11.0 版本为 OpenHarmony 钱包应用增加了完整的数据同步功能。用户现在可以将本地数据(交易、预算、标签等)同步到云端,实现多设备数据同步。新增的数据同步页面提供了直观的同步状态显示和队列管理功能。

核心功能更新
1. 数据同步模型
SyncData 类定义
/// 数据同步模型
class SyncData {
final String id;
final String type; // 'transaction', 'budget', 'tag'
final Map<String, dynamic> data;
final DateTime timestamp;
final String deviceId;
bool isSynced;
SyncData({
required this.id,
required this.type,
required this.data,
required this.timestamp,
required this.deviceId,
this.isSynced = false,
});
}
说明:
- 记录数据类型、内容、时间戳
- 记录来源设备 ID
- 跟踪同步状态
支持的数据类型
| 类型 | 说明 | 示例 |
|---|---|---|
| transaction | 交易数据 | 新增支出、收入 |
| budget | 预算数据 | 预算设置、修改 |
| tag | 标签数据 | 新增标签、编辑标签 |
2. 数据同步服务
DataSyncService 类
/// 数据同步服务
class DataSyncService {
static final List<SyncData> _syncQueue = [];
static bool _isSyncing = false;
/// 添加数据到同步队列
static void addToSyncQueue(
String type,
Map<String, dynamic> data,
String deviceId,
) {
_syncQueue.add(SyncData(
id: DateTime.now().millisecondsSinceEpoch.toString(),
type: type,
data: data,
timestamp: DateTime.now(),
deviceId: deviceId,
));
}
/// 获取待同步数据
static List<SyncData> getPendingSyncData() {
return _syncQueue.where((item) => !item.isSynced).toList();
}
/// 模拟同步数据
static Future<bool> syncData(List<SyncData> dataList) async {
if (_isSyncing) return false;
_isSyncing = true;
try {
// 模拟网络延迟
await Future.delayed(const Duration(seconds: 2));
// 标记为已同步
for (var item in dataList) {
item.isSynced = true;
}
return true;
} catch (e) {
return false;
} finally {
_isSyncing = false;
}
}
/// 获取同步统计
static Map<String, int> getSyncStats() {
return {
'total': _syncQueue.length,
'synced': _syncQueue.where((item) => item.isSynced).length,
'pending': _syncQueue.where((item) => !item.isSynced).length,
};
}
/// 清空同步队列
static void clearSyncQueue() {
_syncQueue.clear();
}
/// 获取同步历史
static List<SyncData> getSyncHistory() {
return List.from(_syncQueue);
}
}
说明:
addToSyncQueue: 添加数据到同步队列getPendingSyncData: 获取待同步的数据syncData: 执行同步操作(模拟网络请求)getSyncStats: 获取同步统计信息clearSyncQueue: 清空同步队列getSyncHistory: 获取完整的同步历史
3. 数据同步页面
同步状态卡片
/// 构建同步状态
Widget _buildSyncStatus(Map<String, int> stats) {
final total = stats['total'] ?? 0;
final synced = stats['synced'] ?? 0;
final pending = stats['pending'] ?? 0;
final syncRate = total > 0 ? (synced / total * 100).toStringAsFixed(1) : '0.0';
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Container(
padding: const EdgeInsets.all(20),
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [Colors.cyan.shade400, Colors.cyan.shade800],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
),
borderRadius: BorderRadius.circular(20),
boxShadow: [
BoxShadow(
color: Colors.cyan.withOpacity(0.3),
blurRadius: 10,
offset: const Offset(0, 5),
),
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'同步状态',
style: Theme.of(context).textTheme.titleMedium?.copyWith(
color: Colors.white,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 20),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
_buildStatItem('总数据', total.toString(), Colors.white),
_buildStatItem('已同步', synced.toString(), Colors.green),
_buildStatItem('待同步', pending.toString(), Colors.orange),
],
),
const SizedBox(height: 20),
ClipRRect(
borderRadius: BorderRadius.circular(8),
child: LinearProgressIndicator(
value: total > 0 ? synced / total : 0,
minHeight: 8,
backgroundColor: Colors.white.withOpacity(0.3),
valueColor: const AlwaysStoppedAnimation<Color>(Colors.green),
),
),
const SizedBox(height: 8),
Text(
'同步进度: $syncRate%',
style: const TextStyle(
color: Colors.white,
fontSize: 12,
fontWeight: FontWeight.w500,
),
),
],
),
),
);
}
说明:
- 显示总数据、已同步、待同步的数量
- 进度条显示同步进度
- 青色渐变背景,区别于其他页面

同步操作按钮
/// 构建同步操作按钮
Widget _buildSyncActions() {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
ElevatedButton.icon(
onPressed: _isSyncing ? null : _performSync,
icon: _isSyncing
? SizedBox(
width: 20,
height: 20,
child: CircularProgressIndicator(
strokeWidth: 2,
valueColor: AlwaysStoppedAnimation<Color>(
Colors.blue.shade700,
),
),
)
: const Icon(Icons.cloud_upload),
label: Text(_isSyncing ? '同步中...' : '立即同步'),
style: ElevatedButton.styleFrom(
backgroundColor: Colors.blue,
foregroundColor: Colors.white,
padding: const EdgeInsets.symmetric(vertical: 12),
),
),
const SizedBox(height: 12),
OutlinedButton.icon(
onPressed: _clearSyncQueue,
icon: const Icon(Icons.delete_outline),
label: const Text('清空队列'),
style: OutlinedButton.styleFrom(
foregroundColor: Colors.red,
side: const BorderSide(color: Colors.red),
padding: const EdgeInsets.symmetric(vertical: 12),
),
),
const SizedBox(height: 12),
Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: Colors.blue.shade50,
borderRadius: BorderRadius.circular(8),
border: Border.all(color: Colors.blue.shade200),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'设备 ID',
style: Theme.of(context).textTheme.bodySmall?.copyWith(
fontWeight: FontWeight.w600,
),
),
const SizedBox(height: 6),
Text(
_deviceId,
style: Theme.of(context).textTheme.bodySmall?.copyWith(
fontFamily: 'monospace',
color: Colors.grey.shade600,
),
),
],
),
),
],
),
);
}
说明:
- 蓝色按钮执行同步
- 红色按钮清空队列
- 显示设备 ID(用于多设备同步标识)
同步历史列表
/// 构建同步历史
Widget _buildSyncHistory(List<SyncData> history) {
if (history.isEmpty) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Container(
padding: const EdgeInsets.all(32),
decoration: BoxDecoration(
color: Colors.grey.shade100,
borderRadius: BorderRadius.circular(12),
),
child: Center(
child: Text(
'暂无同步记录',
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
color: Colors.grey,
),
),
),
),
);
}
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'同步历史 (${history.length})',
style: Theme.of(context).textTheme.titleMedium?.copyWith(
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 12),
...history.asMap().entries.map((entry) {
final item = entry.value;
final isSynced = item.isSynced;
return Padding(
padding: const EdgeInsets.only(bottom: 12),
child: Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
border: Border.all(
color: isSynced ? Colors.green.shade300 : Colors.orange.shade300,
),
borderRadius: BorderRadius.circular(12),
color: isSynced ? Colors.green.shade50 : Colors.orange.shade50,
),
child: Row(
children: [
Container(
width: 40,
height: 40,
decoration: BoxDecoration(
color: isSynced ? Colors.green : Colors.orange,
borderRadius: BorderRadius.circular(8),
),
child: Center(
child: Icon(
isSynced ? Icons.check : Icons.schedule,
color: Colors.white,
size: 20,
),
),
),
const SizedBox(width: 12),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
_getTypeLabel(item.type),
style: const TextStyle(
fontWeight: FontWeight.w600,
fontSize: 14,
),
),
Text(
isSynced ? '已同步' : '待同步',
style: TextStyle(
fontSize: 12,
color: isSynced ? Colors.green : Colors.orange,
fontWeight: FontWeight.w500,
),
),
],
),
const SizedBox(height: 4),
Text(
_formatDateTime(item.timestamp),
style: TextStyle(
fontSize: 11,
color: Colors.grey.shade600,
),
),
],
),
),
],
),
),
);
}).toList(),
],
),
);
}
说明:
- 显示所有同步记录
- 绿色表示已同步,橙色表示待同步
- 显示数据类型、状态、时间戳
UI 变化
数据同步页面布局
┌─────────────────────────────────┐
│ 数据同步 │
├─────────────────────────────────┤
│ 同步状态 │
│ 总数据: 5 已同步: 3 待同步: 2 │
│ [████████░░░░░░░░░░] 60% │
├─────────────────────────────────┤
│ [立即同步] │
│ [清空队列] │
│ 设备 ID: Device-1702... │
├─────────────────────────────────┤
│ 同步历史 (5) │
│ ┌─────────────────────────┐ │
│ │ ✓ 交易数据 已同步 │ │
│ │ 2024-12-24 10:30:45 │ │
│ └─────────────────────────┘ │
│ ┌─────────────────────────┐ │
│ │ ⏱ 预算数据 待同步 │ │
│ │ 2024-12-24 10:35:20 │ │
│ └─────────────────────────┘ │
└─────────────────────────────────┘
同步工作流程
1. 用户在钱包页面添加交易
↓
2. 调用 DataSyncService.addToSyncQueue()
↓
3. 数据添加到同步队列
↓
4. 用户进入数据同步页面
↓
5. 显示待同步数据
↓
6. 用户点击"立即同步"
↓
7. 执行 syncData() 方法
↓
8. 模拟网络请求(2秒延迟)
↓
9. 标记数据为已同步
↓
10. 显示同步成功提示
版本对比
| 功能 | v1.10.0 | v1.11.0 |
|---|---|---|
| 预算提醒 | ✅ | ✅ |
| 预算警告显示 | ✅ | ✅ |
| 实时提醒 | ✅ | ✅ |
| 数据同步模型 | ❌ | ✅ |
| 数据同步服务 | ❌ | ✅ |
| 同步队列管理 | ❌ | ✅ |
| 同步历史记录 | ❌ | ✅ |
| 同步状态显示 | ❌ | ✅ |
| 多设备同步 | ❌ | ✅ |
使用场景
场景 1:查看同步状态
- 进入数据同步页面
- 查看同步状态卡片
- 了解待同步数据数量
- 查看同步进度
场景 2:执行数据同步
- 进入数据同步页面
- 点击"立即同步"按钮
- 等待同步完成(约 2 秒)
- 查看同步成功提示
场景 3:清空同步队列
- 进入数据同步页面
- 点击"清空队列"按钮
- 确认清空操作
- 队列立即清空
场景 4:查看同步历史
- 进入数据同步页面
- 查看同步历史列表
- 了解每条数据的同步状态
- 查看同步时间戳
下一步计划
v1.12.0 将继续增强功能,计划增加:
- 🌙 深色模式支持
- 📊 高级统计分析
- 💾 本地数据持久化
- 🔐 数据加密和安全
感谢使用 OpenHarmony 钱包! 🎉
如有建议或问题,欢迎反馈。
欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net
更多推荐


所有评论(0)