
离线数据自动同步器设计与实现 原创
离线数据自动同步器设计与实现
一、项目概述
基于HarmonyOS 5数据同步策略构建的离线数据自动同步系统,专门针对网络中断恢复后的数据一致性场景进行自动化测试。该系统借鉴《鸿蒙跨端U同步》中游戏场景的多设备数据同步机制,确保设备离线期间的操作在网络恢复后能够正确同步到云端和其他设备。
二、核心架构设计
±--------------------+
离线操作记录器
(Operation Logger)
±---------±---------+
±---------v----------+ ±--------------------+
同步冲突处理器 <—> 云端数据服务
(Conflict Resolver) (Cloud Service)
±---------±---------+ ±--------------------+
±---------v----------+
设备状态监控器
(Device Monitor)
±--------------------+
三、离线操作记录实现
// 离线操作记录服务
public class OfflineOperationService {
private static final String OPERATION_DB = “offline_operations.db”;
private DatabaseHelper dbHelper;
public OfflineOperationService(Context context) {
dbHelper = new DatabaseHelper(context, OPERATION_DB, null, 1);
// 记录离线操作
public void logOperation(String tableName, String operationType,
String recordId, ContentValues values) {
SQLiteDatabase db = dbHelper.getWritableDatabase();
ContentValues logEntry = new ContentValues();
logEntry.put("table_name", tableName);
logEntry.put("operation_type", operationType);
logEntry.put("record_id", recordId);
logEntry.put("operation_data", values.toString());
logEntry.put("timestamp", System.currentTimeMillis());
logEntry.put("synced", 0);
db.insert("operation_log", null, logEntry);
db.close();
// 获取未同步操作
public List<OperationLog> getPendingOperations() {
List<OperationLog> operations = new ArrayList<>();
SQLiteDatabase db = dbHelper.getReadableDatabase();
Cursor cursor = db.query("operation_log",
null,
"synced = 0",
null, null, null, "timestamp ASC");
while (cursor.moveToNext()) {
OperationLog log = new OperationLog(
cursor.getString(0),
cursor.getString(1),
cursor.getString(2),
cursor.getString(3),
cursor.getLong(4),
cursor.getInt(5) == 1
);
operations.add(log);
cursor.close();
db.close();
return operations;
// 标记操作已同步
public void markOperationSynced(long logId) {
SQLiteDatabase db = dbHelper.getWritableDatabase();
ContentValues values = new ContentValues();
values.put("synced", 1);
db.update("operation_log",
values,
"id = ?",
new String[]{String.valueOf(logId)});
db.close();
private static class DatabaseHelper extends SQLiteOpenHelper {
public DatabaseHelper(Context context, String name,
SQLiteDatabase.CursorFactory factory, int version) {
super(context, name, factory, version);
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("CREATE TABLE operation_log (" +
"id INTEGER PRIMARY KEY AUTOINCREMENT," +
"table_name TEXT," +
"operation_type TEXT," +
"record_id TEXT," +
"operation_data TEXT," +
"timestamp INTEGER," +
"synced INTEGER)");
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("DROP TABLE IF EXISTS operation_log");
onCreate(db);
}
四、网络状态监控与同步触发
public class NetworkMonitor {
private ConnectivityManager connectivityManager;
private NetworkCallback networkCallback;
private SyncManager syncManager;
public NetworkMonitor(Context context, SyncManager syncManager) {
this.connectivityManager = (ConnectivityManager)
context.getSystemService(Context.CONNECTIVITY_SERVICE);
this.syncManager = syncManager;
// 开始监控网络状态
public void startMonitoring() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
networkCallback = new NetworkCallback();
connectivityManager.registerDefaultNetworkCallback(networkCallback);
}
// 停止监控
public void stopMonitoring() {
if (networkCallback != null) {
connectivityManager.unregisterNetworkCallback(networkCallback);
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
private class NetworkCallback extends ConnectivityManager.NetworkCallback {
@Override
public void onAvailable(Network network) {
// 网络恢复时触发同步
syncManager.triggerSync();
@Override
public void onLost(Network network) {
// 网络断开时记录状态
syncManager.setOfflineMode(true);
}
五、数据同步冲突处理
public class ConflictResolver {
private static final String LAST_WRITE_WINS = “last_write_wins”;
private static final String SERVER_WINS = “server_wins”;
private static final String CLIENT_WINS = “client_wins”;
private String resolutionStrategy;
public ConflictResolver(String strategy) {
this.resolutionStrategy = strategy;
// 解决数据冲突
public ContentValues resolveConflict(String tableName,
ContentValues localValues,
ContentValues serverValues) {
switch (resolutionStrategy) {
case LAST_WRITE_WINS:
return resolveLastWriteWins(localValues, serverValues);
case SERVER_WINS:
return serverValues;
case CLIENT_WINS:
return localValues;
default:
return mergeValues(localValues, serverValues);
}
// 最后写入优先策略
private ContentValues resolveLastWriteWins(ContentValues local,
ContentValues server) {
long localTimestamp = local.getAsLong("last_modified");
long serverTimestamp = server.getAsLong("last_modified");
return localTimestamp > serverTimestamp ? local : server;
// 合并冲突值
private ContentValues mergeValues(ContentValues local,
ContentValues server) {
ContentValues merged = new ContentValues();
// 合并所有键
Set<String> keys = new HashSet<>();
keys.addAll(local.keySet());
keys.addAll(server.keySet());
for (String key : keys) {
// 特殊处理冲突字段
if (local.containsKey(key) && server.containsKey(key)) {
Object localValue = local.get(key);
Object serverValue = server.get(key);
if (key.equals("last_modified")) {
merged.put(key, Math.max(
local.getAsLong(key),
server.getAsLong(key)
));
else if (!localValue.equals(serverValue)) {
// 默认使用服务器值
merged.put(key, serverValue);
else {
merged.put(key, localValue);
} else if (local.containsKey(key)) {
merged.put(key, local.get(key));
else {
merged.put(key, server.get(key));
}
return merged;
}
六、自动同步管理器
public class AutoSyncManager {
private OfflineOperationService operationService;
private CloudDataService cloudService;
private ConflictResolver conflictResolver;
private Handler handler;
public AutoSyncManager(Context context) {
operationService = new OfflineOperationService(context);
cloudService = new CloudDataService();
conflictResolver = new ConflictResolver("last_write_wins");
handler = new Handler(Looper.getMainLooper());
// 触发同步过程
public void triggerSync() {
if (!isSyncing()) {
new SyncTask().execute();
}
// 执行同步任务
private class SyncTask extends AsyncTask<Void, Void, Boolean> {
@Override
protected Boolean doInBackground(Void... voids) {
List<OperationLog> pendingOperations = operationService.getPendingOperations();
boolean allSuccess = true;
for (OperationLog operation : pendingOperations) {
boolean success = syncOperation(operation);
if (success) {
operationService.markOperationSynced(operation.getId());
else {
allSuccess = false;
}
return allSuccess;
@Override
protected void onPostExecute(Boolean success) {
if (success) {
notifySyncComplete(true);
else {
// 部分失败,安排重试
handler.postDelayed(() -> triggerSync(), 5000);
}
private boolean syncOperation(OperationLog operation) {
try {
switch (operation.getOperationType()) {
case "INSERT":
return cloudService.insertData(
operation.getTableName(),
operation.getContentValues()
);
case "UPDATE":
return syncUpdateOperation(operation);
case "DELETE":
return cloudService.deleteData(
operation.getTableName(),
operation.getRecordId()
);
default:
return false;
} catch (Exception e) {
return false;
}
private boolean syncUpdateOperation(OperationLog operation) {
// 获取服务器当前值
ContentValues serverValues = cloudService.getData(
operation.getTableName(),
operation.getRecordId()
);
// 解决冲突
ContentValues resolvedValues = conflictResolver.resolveConflict(
operation.getTableName(),
operation.getContentValues(),
serverValues
);
// 更新服务器数据
return cloudService.updateData(
operation.getTableName(),
operation.getRecordId(),
resolvedValues
);
}
七、测试框架实现
离线操作模拟器
public class OfflineOperationSimulator {
private AutoSyncManager syncManager;
private boolean isOffline = false;
public OfflineOperationSimulator(Context context) {
syncManager = new AutoSyncManager(context);
// 模拟网络断开
public void simulateNetworkDisconnect() {
isOffline = true;
syncManager.setOfflineMode(true);
// 模拟网络恢复
public void simulateNetworkReconnect() {
isOffline = false;
syncManager.setOfflineMode(false);
syncManager.triggerSync();
// 模拟离线操作
public void simulateOfflineOperation(String table, String operation,
String recordId, ContentValues values) {
if (isOffline) {
syncManager.logOfflineOperation(table, operation, recordId, values);
else {
throw new IllegalStateException("Not in offline mode");
}
// 验证数据同步
public boolean verifyDataSync(String table, String recordId,
ContentValues expectedValues) {
ContentValues cloudValues = syncManager.getCloudData(table, recordId);
return compareValues(expectedValues, cloudValues);
private boolean compareValues(ContentValues expected, ContentValues actual) {
if (expected null || actual null) return false;
if (expected.size() != actual.size()) return false;
for (String key : expected.keySet()) {
if (!actual.containsKey(key)) return false;
if (!expected.get(key).equals(actual.get(key))) return false;
return true;
}
同步一致性测试
public class SyncConsistencyTest {
private OfflineOperationSimulator simulator;
@Before
public void setup() {
simulator = new OfflineOperationSimulator(getContext());
@Test
public void testOfflineInsertSync() {
// 1. 模拟网络断开
simulator.simulateNetworkDisconnect();
// 2. 执行离线插入操作
ContentValues values = new ContentValues();
values.put("id", "test_001");
values.put("name", "Test Product");
values.put("price", 19.99);
values.put("last_modified", System.currentTimeMillis());
simulator.simulateOfflineOperation("products", "INSERT", "test_001", values);
// 3. 模拟网络恢复
simulator.simulateNetworkReconnect();
// 4. 验证数据同步
assertTrue(simulator.verifyDataSync("products", "test_001", values));
@Test
public void testConflictResolution() {
// 1. 准备测试数据
ContentValues serverValues = new ContentValues();
serverValues.put("id", "conflict_001");
serverValues.put("name", "Server Name");
serverValues.put("price", 29.99);
serverValues.put("last_modified", System.currentTimeMillis() - 1000);
simulator.syncManager.cloudService.insertData("products", serverValues);
// 2. 模拟网络断开
simulator.simulateNetworkDisconnect();
// 3. 本地修改数据
ContentValues localValues = new ContentValues();
localValues.put("id", "conflict_001");
localValues.put("name", "Local Name");
localValues.put("price", 39.99);
localValues.put("last_modified", System.currentTimeMillis());
simulator.simulateOfflineOperation("products", "UPDATE", "conflict_001", localValues);
// 4. 模拟网络恢复
simulator.simulateNetworkReconnect();
// 5. 验证冲突解决(应使用最后修改的值)
assertTrue(simulator.verifyDataSync("products", "conflict_001", localValues));
}
八、技术创新点
智能冲突解决:支持多种冲突解决策略配置
可靠同步机制:确保离线操作不丢失
自动恢复:网络恢复后自动触发同步
增量同步:仅同步变更数据,减少流量消耗
全面测试覆盖:模拟各种离线场景验证同步正确性
九、总结
本离线数据自动同步器基于HarmonyOS 5数据同步策略,实现了以下核心价值:
数据一致性:确保离线操作最终与云端数据一致
无缝体验:用户无感知的自动同步过程
灵活配置:可根据业务需求定制冲突解决策略
易于测试:提供完整测试框架验证各种场景
系统借鉴了《鸿蒙跨端U同步》中游戏场景的数据同步机制,将经过验证的离线同步策略应用于通用数据同步场景。未来可结合区块链技术增强数据变更的可追溯性,并与HarmonyOS的分布式能力深度整合,打造更强大的跨设备数据同步解决方案。
