Flutter:Shared Preferences 的奇怪行为

13

我在共享偏好设置方面遇到了不一致的问题。我会尽可能简单地描述它。

我正在使用Firebase Cloud Messaging实现推送通知。当应用处于后台且收到通知时,以下后台处理程序将被调用:

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,我想从共享首选项中读取徽章值,如下所示。

我的小部件使用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。

问题:有什么想法为什么字段没有更新吗?


你找到这个问题的答案了吗? - Sandeep Singh
有人找到了让它工作的方法吗? - KHALED
2个回答

21

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

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

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

在同一模式下,如果共享首选项可以在后台处理程序中修改,请确保在尝试从它们读取时在主隔离区调用此“reload”函数。


reload方法会清除SharePrefs中的数据。 - Sandeep Singh
你能否请详细解释一下这个问题? - Sandeep Singh
1
谢谢您!对于任何想了解的人,这是 .reload() 的文档: 从主机平台获取最新值。 使用此方法观察在应用程序运行时在本地代码中进行的修改(而不使用插件)。 - MickaelHrndz
对我来说没有用,问题还是跟提问中描述的一样! - KHALED

1

SharedPreferences或任何其他本地存储在_firebaseMessagingBackgroundHandler中无法工作。

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

简而言之: 当应用程序从终止状态打开时,会触发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);
  }
});

1
当用户点击通知本身时,将触发onMessageOpenedApp。 - KHALED

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接