Flutter:共享首选项的奇怪行为

Posted

技术标签:

【中文标题】Flutter:共享首选项的奇怪行为【英文标题】:Flutter : Strange behavior of Shared Preferences 【发布时间】:2021-03-05 17:59:30 【问题描述】:

我遇到了共享首选项值不一致的问题。我会尽量简单地描述它。

我正在使用 Firebase 云消息传递推送通知。当应用程序处于后台并收到通知时,将调用下面的后台处理程序。

Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async 
  final SharedPreferences prefs = await SharedPreferences.getInstance();
  final int counter = (prefs.getInt('badge') ?? 0) + 1;

  prefs.setInt('badge', counter).then((bool success) 
    print(counter);
  );

我的小部件使用 WidgetsBindingObserver 来确定生命周期状态。当我进入应用程序时,该小部件的状态为 onResume,我想从这样的共享首选项中读取该徽章值。

void didChangeAppLifecycleState(AppLifecycleState state) 
    if (state == AppLifecycleState.resumed) 
      final SharedPreferences prefs = await SharedPreferences.getInstance();
      final int counter = (prefs.getInt('badge') ?? 0); 
      print(counter);
    
  

场景 1:

应用打开,收到通知 - 将徽章字段设置为 1。 应用在后台,收到通知 - 后台处理程序将徽章字段设置为 2。 应用程序已恢复,读取徽章字段,它仍然是 1。

场景 2:

应用打开,收到通知 - 将徽章字段设置为 1。 应用在后台,收到通知 - 后台处理程序将徽章字段设置为 2。 应用在后台,收到通知 - 后台处理程序将徽章字段设置为 3。 应用程序已恢复,读取徽章字段,它仍然是 1。

问题:知道为什么字段没有更新吗?

【问题讨论】:

你找到这个问题的答案了吗? 【参考方案1】:

SharedPreferences 或任何其他本地存储在 _firebaseMessagingBackgroundHandler 中不起作用。

您应该在 getInitialMessage 或 onMessageOpenedApp 上捕获它。 https://firebase.flutter.dev/docs/messaging/notifications/

TL;DR: 当应用程序从终止状态打开时触发 getInitialMessage。当应用程序从后台状态打开时会触发 onMessageOpenedApp。

FirebaseMessaging.instance.getInitialMessage().then((RemoteMessage message) 
  if (message != null) 
    Navigator.of(context).pushNamed('/messages', arguments: message.data);
  
);

FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) 
  if (message != null) 
    Navigator.of(context).pushNamed('/messages', arguments: message.data);
  
);

【讨论】:

【参考方案2】:

SharedPreferences 可用于后台事件处理程序。问题是后台处理程序在不同的隔离中运行,因此,当您尝试获取数据时,共享首选项实例为空。为避免这种情况,您只需强制刷新:

SharedPreferences prefs= await SharedPreferences.getInstance();
await prefs.reload();
final int counter = (prefs.getInt('badge') ?? 0);

在相同的模式下,如果可以在后台 hadler 中修改共享首选项,请确保在尝试读取它们的主隔离时调用此“重新加载”函数。

【讨论】:

reload 方法会清除共享首选项中的数据 能否请您进一步说明这一点 谢谢你!对于任何想知道的人,这里是 .reload() 的文档: 从主机平台获取最新值。使用此方法可以在应用程序运行时观察在本机代码中所做的修改(不使用插件)。

以上是关于Flutter:共享首选项的奇怪行为的主要内容,如果未能解决你的问题,请参考以下文章

Flutter:使用共享首选项插件存储保存的收藏列表

如何将对象列表中的布尔收藏夹保存到 Flutter 中的共享首选项

Flutter ios 共享首选项显示 setstring on null 错误

Flutter:使用共享首选项时对 null 的方法调用

Flutter 存储共享首选项中的自定义类列表

Flutter 中的共享首选项错误 - Mac 上的 iOS