Flutter 当应用程序关闭或处于前台时,抖动获取_存储实例冲突

Flutter 当应用程序关闭或处于前台时,抖动获取_存储实例冲突,flutter,firebase-cloud-messaging,flutter-getx,Flutter,Firebase Cloud Messaging,Flutter Getx,我正在使用GetX并为我的Flitter应用程序获取存储空间。我的应用程序已按预期与firebase_消息一起工作 当应用程序处于后台时,我使用get_存储来保存当前消息,在尝试读取消息列表时恢复(点击消息)时,与进入后台之前保持相同 复制步骤 开放应用程序 装载服务(包括FCM) 去前台 发送/接收消息保存到存储密钥(可查看存储 (有留言) 轻触,恢复应用程序存储密钥列表似乎与之前一样 背景 我假设我缺少一些反映存储更改的操作。我很抱歉,我真的不知道如何使代码尽可能可读 主要 Future

我正在使用GetX并为我的Flitter应用程序获取存储空间。我的应用程序已按预期与firebase_消息一起工作

当应用程序处于后台时,我使用get_存储来保存当前消息,在尝试读取消息列表时恢复(点击消息)时,与进入后台之前保持相同

复制步骤

  • 开放应用程序
  • 装载服务(包括FCM)
  • 去前台
  • 发送/接收消息保存到存储密钥(可查看存储 (有留言)
  • 轻触,恢复应用程序存储密钥列表似乎与之前一样 背景
我假设我缺少一些反映存储更改的操作。我很抱歉,我真的不知道如何使代码尽可能可读

主要

Future main()异步{
WidgetsFlutterBinding.ensureInitialized();
wait ServicesSer().dependencies();
runApp(
GetMaterialApp(
标题:“申请”,
initialRoute:AppPages.INITIAL,
//showPerformanceOverlay:正确,
语言环境:TranslationService.locale,
fallbackLocale:TranslationService.fallbackLocale,
翻译:TranslationService(),
主题:theme.light,
黑暗主题:主题,黑暗,
themeMode:Wait Get.find().getSetting(
设置键:“主题”,
设置值:“灯光”,
) ==
“光”
?表情灯
:theemode.dark,
getPages:AppPages.routes,
debugShowCheckedModeBanner:false,
),
);
}
服务

class ServicesSer extends Bindings {
  @override
  Future<void> dependencies() async {

    //storageCtrl
    await Get.putAsync<StorageCtrl>(() async {
      await GetStorage.init();
      final storageCtrl = StorageCtrl();
      await storageCtrl.storageCtrlInit();
      return storageCtrl;
    }, permanent: true);

    //notifications
    await Get.putAsync<NotificationsCtrl>(() async {
      final notificationsCtrl = NotificationsCtrl();
      await notificationsCtrl.notificationsInit();
      return notificationsCtrl;
    }, permanent: true);

    //firebase messaging init
    await Get.putAsync<FirebaseMessageSer>(() async {
      await Firebase.initializeApp();
      final firebaseMessengerSer = FirebaseMessageSer();
      await firebaseMessengerSer.firebaseMessageSerInit();
      return firebaseMessengerSer;
    }, permanent: true);
  }
}
类服务服务器扩展绑定{
@凌驾
Future dependencies()异步{
//storageCtrl
等待Get.putAsync(()async{
等待GetStorage.init();
final-storageCtrl=storageCtrl();
等待storageCtrl.storageCtrlInit();
返回storageCtrl;
},永久性:正确);
//通知
等待Get.putAsync(()async{
最终通知SCTRL=通知SCTRL();
等待通知sctrl.notificationsInit();
返回通知SCTRL;
},永久性:正确);
//firebase消息传递初始化
等待Get.putAsync(()async{
等待Firebase.initializeApp();
final FirebaseMessenger=FirebaseMessageSer();
等待FirebaseMessenger.firebaseMessageSerInit();
返回FirebaseMessenger;
},永久性:正确);
}
}
FireBaseMesser

class FirebaseMessageSer extends GetxService {
  NotificationsCtrl notificationsCtrl = Get.find<NotificationsCtrl>();
  late FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin;

  @override
  Future<void> onInit() async {
    super.onInit();
  }

  @override
  void onReady() {
    super.onReady();
  }

  @override
  void onClose() {
    super.onClose();
  }

  Future<void> firebaseMessageSerInit() async {
    await FirebaseMessaging.instance
        .setForegroundNotificationPresentationOptions(
      alert: false,
      badge: false,
      sound: false,
    );
    ;

    FirebaseMessaging.instance.getInitialMessage().then((message) async {
      print('getInitialMessage');
    });

    FirebaseMessaging.onMessage.listen((message) {
      print('onMessage');
      notificationsCtrl.showNotification(message: message);
    });

    FirebaseMessaging.onMessageOpenedApp.listen((message) {
      print('onMessageOpenedApp');
      notificationsCtrl.showNotification(message: message);
    });

    FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);

    print(await FirebaseMessaging.instance.getToken());
  }
}

**//when app is closed or in foreground this function will handle notification**
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
  print('Handling a background message ${message.messageId}');

 ///most probably here is the issue, I need to initiate ctrls again as in foreground they are not longer in memory
 /// creating another instance of storage
 ///showNotification (bellow) saves the message to storage but when I resume the app
 /// the other instance of storage has not been updated
  Get.put(StorageCtrl());
  final notificationsCtrl = Get.put(NotificationsCtrl());
  notificationsCtrl.showNotification(message: message);
}
class FirebaseMessageSer扩展了GetxService{
NotificationsCtrl NotificationsCtrl=Get.find();
晚震颤局部震颤局部震颤局部震颤;
@凌驾
Future onInit()异步{
super.onInit();
}
@凌驾
void onReady(){
super.onReady();
}
@凌驾
void onClose(){
super.onClose();
}
未来firebaseMessageSerInit()异步{
等待FirebaseMessaging.instance
.setForegroundNotificationPresentationOptions(
警告:错误,
徽章:假,
声音:错,
);
;
FirebaseMessaging.instance.getInitialMessage().then((消息)异步{
打印('getInitialMessage');
});
FirebaseMessaging.onMessage.listen((消息){
打印(“onMessage”);
notificationsCtrl.showNotification(消息:消息);
});
FirebaseMessaging.onMessageGeoPenedApp.listen((消息){
打印('onMessagePenedApp');
notificationsCtrl.showNotification(消息:消息);
});
FirebaseMessagingBackgroundMessage(_firebaseMessagingBackgroundHandler);
打印(等待FirebaseMessaging.instance.getToken());
}
}
**//当应用程序关闭或处于前台时,此函数将处理通知**
Future\u firebaseMessagingBackgroundHandler(远程消息)异步{
打印('处理背景消息${message.messageId}');
///最可能的问题是,我需要再次启动CTRL,因为在前台它们不再在内存中
///创建另一个存储实例
///showNotification(bellow)将消息保存到存储器中,但在我恢复应用程序时
///另一个存储实例尚未更新
Get.put(StorageCtrl());
final notificationsCtrl=Get.put(notificationsCtrl());
notificationsCtrl.showNotification(消息:消息);
}
StorageCtrl

class StorageCtrl extends GetxController {
  final GetStorage storage = GetStorage();

  @override
  Future<void> onInit() async {
    // await storage.erase();
    super.onInit();
  }

  @override
  void onReady() {
    super.onReady();
  }

  @override
  void onClose() {
    super.onClose();
  }

  Future<void> storageCtrlInit() async {
    await initTheme();
  }

  ///////////////////////////////////////////////////////////////////////
  ///THEME
  Future<void> initTheme() async {
    final userTheme = await getSetting(
      settingKey: 'THEME',
      settingValue: 'light',
    );

    ///FIXME status bar on android has wrong color
    if (userTheme == 'light') {
      SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle(
        statusBarColor: lightPrimaryAppColor,
      ));
      SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle.dark);
    } else {
      SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle(
        statusBarColor: darkPrimaryAppColor,
      ));
      SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle.light);
    }
  }

  Future<void> changeTheme() async {
    final theme = Get.isDarkMode ? ThemeMode.light : ThemeMode.dark;

    setSetting(
      settingKey: 'THEME',
      settingValue: theme.toString().split('.')[1],
    );
    await initTheme();
    Get.changeThemeMode(theme);
  }

 
  ///////////////////////////////////////////////////////////////////////
  ///STORAGE
  /// settingValue will be a default value return if key is null
  dynamic getSetting(
      {required String settingKey, dynamic settingValue})  {
    final setting = storage.read(settingKey);
    return setting != null ? setting : settingValue;
  }

  Future<void> setSetting(
      {required String settingKey, dynamic settingValue}) async {
    await storage.write(settingKey, settingValue);
    print('settingKey: $settingKey - settingValue: $settingValue');
  }
}
class StorageCtrl扩展了GetxController{
最终GetStorage=GetStorage();
@凌驾
Future onInit()异步{
//等待存储。擦除();
super.onInit();
}
@凌驾
void onReady(){
super.onReady();
}
@凌驾
void onClose(){
super.onClose();
}
Future storageCtrlInit()异步{
等待初始化主题();
}
///////////////////////////////////////////////////////////////////////
///主题
Future initTheme()异步{
最终用户主题=等待getSetting(
设置键:“主题”,
设置值:“灯光”,
);
///android上的FIXME状态栏颜色错误
if(userTheme=='light'){
SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle(
statusBarColor:lightPrimaryAppColor,
));
SystemChrome.SetSystemEmioVerlayStyle(SystemUiOverlayStyle.dark);
}否则{
SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle(
statusBarColor:darkPrimaryAppColor,
));
SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle.light);
}
}
Future changeTheme()异步{
最终主题=Get.isDarkMode?themmode.light:themmode.dark;
设置(
设置键:“主题”,
settingValue:theme.toString().split('.')[1],
);
等待初始化主题();
Get.changethemode(主题);
}
///////////////////////////////////////////////////////////////////////
///储藏
///如果键为null,则settingValue将是一个默认值返回
动态getSetting(
{必需的字符串设置键,动态设置值}){
最终设置=存储读取(设置键);
返回设置!=null?设置:settingValue;
}
未来设定(
{必需的Strin
class StorageCtrl extends GetxController {
  final GetStorage storage = GetStorage();

  @override
  Future<void> onInit() async {
    // await storage.erase();
    super.onInit();
  }

  @override
  void onReady() {
    super.onReady();
  }

  @override
  void onClose() {
    super.onClose();
  }

  Future<void> storageCtrlInit() async {
    await initTheme();
  }

  ///////////////////////////////////////////////////////////////////////
  ///THEME
  Future<void> initTheme() async {
    final userTheme = await getSetting(
      settingKey: 'THEME',
      settingValue: 'light',
    );

    ///FIXME status bar on android has wrong color
    if (userTheme == 'light') {
      SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle(
        statusBarColor: lightPrimaryAppColor,
      ));
      SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle.dark);
    } else {
      SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle(
        statusBarColor: darkPrimaryAppColor,
      ));
      SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle.light);
    }
  }

  Future<void> changeTheme() async {
    final theme = Get.isDarkMode ? ThemeMode.light : ThemeMode.dark;

    setSetting(
      settingKey: 'THEME',
      settingValue: theme.toString().split('.')[1],
    );
    await initTheme();
    Get.changeThemeMode(theme);
  }

 
  ///////////////////////////////////////////////////////////////////////
  ///STORAGE
  /// settingValue will be a default value return if key is null
  dynamic getSetting(
      {required String settingKey, dynamic settingValue})  {
    final setting = storage.read(settingKey);
    return setting != null ? setting : settingValue;
  }

  Future<void> setSetting(
      {required String settingKey, dynamic settingValue}) async {
    await storage.write(settingKey, settingValue);
    print('settingKey: $settingKey - settingValue: $settingValue');
  }
}
Future<void> showNotification({required RemoteMessage message}) async {
    print('showNotification');

    final data = message.data;
    
    **//when on background, I can see that adding the message to the storage works as expected**
    await addRemoteMessage(message: message);

    NotificationDetails _notificationDetails;

    switch (data['notificationType']) {
      case 'bigImagePushNotification':
        _notificationDetails =
            await notificationDetailsBigImage(message: message);
        break;
      case 'smallImagePushNotification':
        _notificationDetails =
            await notificationDetailsTileImage(message: message);
        break;
      default:
        _notificationDetails = notificationDetailsNormal(message: message);
    }

    flutterLocalNotificationsPlugin.show(
      message.notification.hashCode,
      data['title'],
      data['excerpt'],
      _notificationDetails,
      payload: message.messageId,
    );
    
  }

Future<void> addRemoteMessage({
    required RemoteMessage message,
  }) async {
    final _message = MessageModel(
      message.messageId!,
      message.data['action'],
      message.data['id'],
      message.data['notificationType'],
      message.data['title'],
      message.data['excerpt'],
      message.data['featuredImage'],
      // DateTim.toIso8601String(),
    );

    var _messages = await getRemoteMessages();
    _messages.add(_message);

    await saveRemoteMessages(messages: _messages);
  }

Future<List<MessageModel>> getRemoteMessages() async {
    var messageList = <MessageModel>[];

    final list = await storageCtrl.getSetting(
      settingKey: 'MESSAGES',
      settingValue: <Map<String, dynamic>>[],
    );

    for (var _message in list) {
      messageList.add(MessageModel.fromJson(_message));
    }

    return messageList;
  }

Future<void> saveRemoteMessages({
    required List<MessageModel> messages,
  }) async {
    var _messagesList = <Map<String, dynamic>>[];

    for (var _message in messages) {
      _messagesList.add(json.decode(jsonEncode(_message)));
    }

    await storageCtrl.setSetting(
      settingKey: 'MESSAGES',
      settingValue: _messagesList,
    );
  }


Future onSelectNotification(String? payload) async {
    print('onSelectNotification');

    **/////When selected notification triggers app Resumes**
    ** //// but getRemoteMessage have the same list before going on background**

    final _message = await getRemoteMessage(messageId: (payload)!);
    await removeRemoteMessage(messageId: payload);
    await notificationHandler(
      message: _message,
    );
  }