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

are*_*ech 5 sharedpreferences flutter firebase-cloud-messaging

我有不一致的共享首选项值的问题。我将尝试尽可能简单地描述它。

我正在使用 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);
  });
}
Run Code Online (Sandbox Code Playgroud)

我的小部件使用 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);
    }
  }

Run Code Online (Sandbox Code Playgroud)

场景一:

  • 应用程序打开,通知进来 - 将徽章字段设置为 1。
  • 应用程序在后台,通知进来了 - 后台处理程序将徽章字段设置为 2。
  • 应用程序恢复,阅读那个徽章字段,它仍然是 1。

场景2:

  • 应用程序打开,通知进来 - 将徽章字段设置为 1。
  • 应用程序在后台,通知进来了 - 后台处理程序将徽章字段设置为 2。
  • 应用程序在后台,通知进来了 - 后台处理程序将徽章字段设置为 3。
  • 应用程序恢复,阅读那个徽章字段,它仍然是 1。

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

小智 5

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

SharedPreferences prefs= await SharedPreferences.getInstance();
await prefs.reload();
final int counter = (prefs.getInt('badge') ?? 0);
Run Code Online (Sandbox Code Playgroud)

在相同模式下,如果共享首选项可以在后台 hadler 中修改,请确保在主隔离中调用此“重新加载”功能,当您尝试从他们那里读取时。


har*_*mez 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);
  }
});
Run Code Online (Sandbox Code Playgroud)