Flutter如何在日期变更时自动刷新Riverpod FutureProvider数据源列表?
问题解答
你的猜测是对的——手机进入休眠状态(比如Android的Doze模式、iOS的低功耗模式)时,后台运行的定时Stream会被系统限制暂停,导致Stream.periodic无法按预期每分钟执行日期检查,自然触发不了日期变化的事件,所以次日打开应用时还是旧数据。
解决办法
1. 监听应用前后台切换,主动触发检查
不需要依赖后台定时任务,而是在应用从后台回到前台时,主动对比当前日期和上次存储的日期,判断是否需要刷新数据。
先创建一个监听应用生命周期的Provider:
final appLifecycleProvider = StreamProvider<AppLifecycleState>((ref) { final controller = StreamController<AppLifecycleState>(); final observer = _LifecycleObserver(controller); WidgetsBinding.instance.addObserver(observer); ref.onDispose(() { WidgetsBinding.instance.removeObserver(observer); controller.close(); }); return controller.stream; }); class _LifecycleObserver extends WidgetsBindingObserver { final StreamController<AppLifecycleState> controller; _LifecycleObserver(this.controller); @override void didChangeAppLifecycleState(AppLifecycleState state) { controller.add(state); } }
再修改你的数据Provider,结合生命周期和日期检查:
final findTodayDashboardTaskProvider = FutureProvider.autoDispose<List<GdTask>>((ref) async { // 监听应用回到前台,触发刷新 ref.listen(appLifecycleProvider, (_, state) { if (state == AppLifecycleState.resumed) { ref.invalidateSelf(); } }); const dayCheckerKey = 'dayCheckerTimestamp'; final prefs = ref.read(sharedPrefsProvider); final now = DateTime.now(); final lastTimestampStr = prefs.getString(dayCheckerKey); // 检查日期是否变化 if (lastTimestampStr != null) { final lastDate = DateTime.parse(lastTimestampStr); final dayChanged = now.day != lastDate.day || now.month != lastDate.month || now.year != lastDate.year; if (dayChanged) { prefs.setString(dayCheckerKey, now.toIso8601String()); } } else { prefs.setString(dayCheckerKey, now.toIso8601String()); } // 原有加载当日数据的逻辑 return await loadTodayTasks(); });
2. 简化StreamProvider,仅在应用活跃时运行
如果还是想用Stream实现,可以让定时检查只在应用处于活跃状态时执行,避免被系统后台限制:
final newDayProvider = StreamProvider<DateTime?>((ref) async* { const dayCheckerKey = 'dayCheckerTimestamp'; final prefs = ref.read(sharedPrefsProvider); final lifecycleStream = ref.watch(appLifecycleProvider); // 初始化时先检查一次 final initNow = DateTime.now(); final initLastStr = prefs.getString(dayCheckerKey); if (initLastStr != null) { final initLastDate = DateTime.parse(initLastStr); if (initNow.day != initLastDate.day || initNow.month != initLastDate.month || initNow.year != initLastDate.year) { prefs.setString(dayCheckerKey, initNow.toIso8601String()); yield initNow; } } else { prefs.setString(dayCheckerKey, initNow.toIso8601String()); } // 监听生命周期,仅在活跃时执行定时检查 await for (final state in lifecycleStream) { if (state == AppLifecycleState.resumed) { // 回到前台立即检查 final resumeNow = DateTime.now(); final resumeLastStr = prefs.getString(dayCheckerKey); if (resumeLastStr != null) { final resumeLastDate = DateTime.parse(resumeLastStr); if (resumeNow.day != resumeLastDate.day || resumeNow.month != resumeLastDate.month || resumeNow.year != resumeLastDate.year) { prefs.setString(dayCheckerKey, resumeNow.toIso8601String()); yield resumeNow; } } // 活跃期间每分钟检查一次,日期变化后停止定时 await for (final _ in Stream.periodic(const Duration(minutes: 1))) { final checkNow = DateTime.now(); final checkLastStr = prefs.getString(dayCheckerKey); if (checkLastStr != null) { final checkLastDate = DateTime.parse(checkLastStr); final changed = checkNow.day != checkLastDate.day || checkNow.month != checkLastDate.month || checkNow.year != checkLastDate.year; if (changed) { prefs.setString(dayCheckerKey, checkNow.toIso8601String()); yield checkNow; break; } } } } } });
3. 轻量方案:Provider初始化时直接检查日期
如果你的场景只需要用户打开应用时刷新数据,不需要后台实时监听,直接在数据Provider初始化时检查日期即可:
final findTodayDashboardTaskProvider = FutureProvider.autoDispose<List<GdTask>>((ref) async { const dayCheckerKey = 'dayCheckerTimestamp'; final prefs = ref.read(sharedPrefsProvider); final now = DateTime.now(); final lastTimestampStr = prefs.getString(dayCheckerKey); bool needRefresh = false; if (lastTimestampStr != null) { final lastDate = DateTime.parse(lastTimestampStr); needRefresh = now.day != lastDate.day || now.month != lastDate.month || now.year != lastDate.year; } else { needRefresh = true; } if (needRefresh) { prefs.setString(dayCheckerKey, now.toIso8601String()); // 这里可以添加清除缓存等逻辑 } // 加载当日数据 return await loadTodayTasks(); });
内容的提问来源于stack exchange,提问作者Davout
相关产品推荐
相关产品推荐

