Flutter使用shared_preferences时不同函数间数据不同步如何解决
根本原因
你遇到的是 android_alarm_manager_plus 最常见的踩坑点:它触发的定时回调运行在独立的Dart Isolate中,和App主业务的Isolate内存完全隔离,不存在任何共享的内存变量。
你在主Isolate中初始化的全局storage.sharedPrefs单例,和Alarm回调Isolate中访问的SharedPreferences是完全独立的两个实例,各自持有内存缓存,默认不会和磁盘自动同步,所以才会出现两边读写不一致的情况。你之前在主Isolate调用reload()对Alarm的Isolate完全无效,反之亦然。
解决方案
按以下步骤修改即可解决同步问题:
- Alarm回调内每次读写前强制重载
在你的schedule()函数最开始,先获取当前Isolate的SharedPreferences实例,强制从磁盘同步最新数据,忽略本地缓存:
Future<void> schedule() async { // 独立Isolate内单独获取实例,不要用主Isolate的全局单例 final prefs = await SharedPreferences.getInstance(); // 强制从磁盘重载,拉取最新值 await prefs.reload(); // 后续所有读写都用这个prefs实例 final lastSchedulingDate = prefs.getString('dateOfLastScheduling'); // 你的业务调度逻辑... // 所有写入操作必须await,确保刷到磁盘 await prefs.setString('dateOfLastScheduling', DateTime.now().toIso8601String()); await prefs.setStringList('scheduledTasks', yourNewTaskList); }
- 主Isolate修改后确保落盘
主Isolate所有对SharedPreferences的写入操作,必须await对应的set方法返回,不要省略异步等待,避免修改只存在于内存缓存还没刷到磁盘。 - 跨Isolate状态更新通知(可选,用于UI即时刷新)
如果需要主Isolate的UI即时感知到Alarm回调里的修改,可以通过Isolate通信机制实现:
- 主Isolate提前注册通信端口:
import 'dart:isolate'; // 主Isolate初始化阶段执行 final mainReceivePort = ReceivePort(); IsolateNameServer.registerPortWithName(mainReceivePort.sendPort, 'main_notify_port'); // 监听Alarm回调的更新通知 mainReceivePort.listen((message) { if (message == 'sp_updated') { // 主Isolate重载SharedPreferences缓存 await storage.sharedPrefs.reload(); // 刷新任务列表UI即可 setState(() {}); } });
- 在
schedule()函数写入完成后发送通知:
// schedule()函数写入操作完成后添加 final mainPort = IsolateNameServer.lookupPortByName('main_notify_port'); mainPort?.send('sp_updated');
注意事项
SharedPreferences的内存单例仅在单个Isolate内有效,跨Isolate的状态同步必须依赖磁盘作为中间层,配合强制重载+消息通知实现完全一致的读写效果。
内容的提问来源于stack exchange,提问作者denw
相关产品推荐
相关产品推荐

