保证不同平台数据一致性
- 底层原理:
SharedPreferences
在Android上基于XML
文件存储数据,在iOS上是基于NSUserDefaults
存储数据。虽然存储机制不同,但Flutter的SharedPreferences
插件通过统一的接口抽象,为开发者提供了一致的操作方式。
- 关键在于确保在不同平台上对数据的写入和读取遵循相同的逻辑和格式。例如,在数据类型转换上要保持一致,如将
int
、double
、bool
、String
等类型正确转换和存储。
- 具体实现:
- 数据类型一致性:
- 在写入数据时,确保在不同平台上以相同的数据类型存储。比如,将一个
int
值写入SharedPreferences
,无论是在Android还是iOS,都应该以int
类型正确存储。在Flutter中,SharedPreferences
插件会处理这些类型转换,但开发者要注意传递正确的数据类型。例如:
final prefs = await SharedPreferences.getInstance();
await prefs.setInt('counter', 10);
- 版本控制:
- 可以在应用中引入版本号机制。每次对存储数据的结构或格式进行更改时,更新版本号。在读取数据时,先检查版本号,根据版本号进行相应的数据迁移操作。例如:
final prefs = await SharedPreferences.getInstance();
int? version = prefs.getInt('dataVersion');
if (version == null) {
// 初始化版本号
await prefs.setInt('dataVersion', 1);
// 初始化数据
} else if (version == 1) {
// 执行版本1的数据迁移逻辑
await prefs.setInt('dataVersion', 2);
}
优化高并发读写性能
- 底层原理:
- Android:
SharedPreferences
的写入操作是异步的,通过commit()
或apply()
方法。commit()
方法是同步的,会阻塞当前线程直到写入完成;apply()
方法是异步的,会将写入操作提交到一个单线程的DiskWriteThread
队列中执行。读取操作是同步的,直接从内存中的SharedPreferencesImpl
对象获取数据,如果内存中没有,则从磁盘加载。
- iOS:
NSUserDefaults
的读写操作相对简单,读取直接从内存缓存中获取,写入则是异步地将更改写入磁盘。但在高并发场景下,也可能出现数据冲突问题。
- 具体实现:
- 读写队列:
- 可以创建一个单线程的队列来处理
SharedPreferences
的读写操作。使用compute
函数在一个单独的隔离计算线程中执行读写任务,避免在主线程中出现高并发冲突。例如:
import 'dart:async';
import 'dart:isolate';
class SharedPrefsQueue {
final ReceivePort _receivePort = ReceivePort();
static const _channelName = 'shared_prefs_queue';
SharedPrefsQueue() {
Isolate.spawn(_worker, _receivePort.sendPort);
}
static Future<void> _worker(SendPort sendPort) async {
final ReceivePort receivePort = ReceivePort();
sendPort.send(receivePort.sendPort);
await for (final message in receivePort) {
if (message is Function) {
message();
}
}
}
Future<void> performOperation(Future<void> Function() operation) async {
final sendPort = await _receivePort.first;
sendPort.send(operation);
}
}
- 批量操作:
- 避免频繁的小读写操作,将多个读写操作合并为一次批量操作。例如,将多个数据的写入操作合并:
final prefs = await SharedPreferences.getInstance();
final batch = prefs.edit();
batch.setInt('key1', 1);
batch.setString('key2', 'value2');
await batch.apply();
- 缓存机制:
- 在内存中维护一个缓存,对于频繁读取的数据,先从缓存中获取。只有在缓存中不存在或者数据过期时,才从
SharedPreferences
中读取。在写入数据时,同时更新缓存,确保缓存与SharedPreferences
的数据一致性。例如:
class SharedPrefsCache {
final Map<String, dynamic> _cache = {};
final SharedPreferences _prefs;
SharedPrefsCache(this._prefs);
Future<dynamic> getValue(String key) async {
if (_cache.containsKey(key)) {
return _cache[key];
}
final value = await _prefs.get(key);
_cache[key] = value;
return value;
}
Future<void> setValue(String key, dynamic value) async {
await _prefs.setString(key, value.toString());
_cache[key] = value;
}
}