name: mobile-offline-support description: 离线优先移动应用,具有本地存储、同步队列、冲突解决功能。用于离线功能、数据同步、连接性处理、或遇到同步冲突、队列管理、存储限制、网络切换错误。
移动离线支持
构建离线优先移动应用,具有本地存储和同步功能。
React Native 实现
import AsyncStorage from '@react-native-async-storage/async-storage';
import NetInfo from '@react-native-community/netinfo';
class OfflineManager {
constructor() {
this.syncQueue = [];
this.isOnline = true;
// 同步队列中最大项目数,超出时丢弃最旧的项目
this.MAX_SYNC_QUEUE_LENGTH = 1000;
NetInfo.addEventListener(state => {
this.isOnline = state.isConnected;
if (this.isOnline) this.processQueue();
});
}
/**
* 从服务器获取数据。
* TODO: 替换为实际的 API 端点实现。
*/
async fetchFromServer(key) {
try {
// 示例实现 - 替换为您的 API
const response = await fetch(`${API_BASE_URL}/data/${key}`);
if (!response.ok) {
throw new Error(`服务器返回 ${response.status}`);
}
return await response.json();
} catch (error) {
console.error('fetchFromServer 失败:', error);
throw new Error(`获取 ${key} 失败: ${error.message}`);
}
}
/**
* 同步数据到服务器。
* TODO: 替换为实际的 API 端点实现。
*/
async syncToServer(key, data) {
try {
// 示例实现 - 替换为您的 API
const response = await fetch(`${API_BASE_URL}/data/${key}`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data)
});
if (!response.ok) {
throw new Error(`服务器返回 ${response.status}`);
}
return await response.json();
} catch (error) {
console.error('syncToServer 失败:', error);
throw new Error(`同步 ${key} 失败: ${error.message}`);
}
}
async getData(key) {
const cached = await AsyncStorage.getItem(key);
if (cached) return JSON.parse(cached);
if (this.isOnline) {
const data = await this.fetchFromServer(key);
await AsyncStorage.setItem(key, JSON.stringify(data));
return data;
}
return null;
}
async saveData(key, data) {
await AsyncStorage.setItem(key, JSON.stringify(data));
if (this.isOnline) {
await this.syncToServer(key, data);
} else {
// 添加到队列
this.syncQueue.push({ key, data, timestamp: Date.now() });
// 强制执行队列边界 - 超出时丢弃最旧的项目
while (this.syncQueue.length > this.MAX_SYNC_QUEUE_LENGTH) {
const discarded = this.syncQueue.shift();
console.warn(`同步队列已满 - 丢弃最旧项目: ${discarded.key}`);
}
// 持久化修剪后的队列
await AsyncStorage.setItem('syncQueue', JSON.stringify(this.syncQueue));
}
}
async processQueue() {
const failedItems = [];
for (const item of this.syncQueue) {
try {
await this.syncToServer(item.key, item.data);
} catch (err) {
console.error('同步失败:', err);
failedItems.push(item);
}
}
this.syncQueue = failedItems;
if (failedItems.length === 0) {
await AsyncStorage.removeItem('syncQueue');
} else {
await AsyncStorage.setItem('syncQueue', JSON.stringify(failedItems));
}
}
}
冲突解决
function resolveConflict(local, server) {
// 最后写入者胜出
if (local.updatedAt > server.updatedAt) return local;
return server;
// 或者合并更改
// return { ...server, ...local };
}
UI 指示器
function OfflineIndicator() {
const [isOnline, setIsOnline] = useState(true);
useEffect(() => {
return NetInfo.addEventListener(state => {
setIsOnline(state.isConnected);
});
}, []);
if (isOnline) return null;
return (
<View style={styles.banner}>
<Text>您处于离线状态。更改将在连接时同步。</Text>
</View>
);
}
最佳实践
- 本地缓存频繁访问的数据
- 队列操作以进行后续同步
- 显示清晰的离线指示器
- 优雅地处理同步冲突
- 压缩存储的数据
- 彻底测试离线场景
原生实现
参见 references/native-implementations.md 以了解:
- iOS Core Data 与同步管理器
- Android Room 数据库与 WorkManager 同步
避免
- 假设连接性
- 在同步失败时丢失数据
- 无限制的队列增长
- 不安全地同步敏感数据