如何解决当应用程序关闭或在前台时,flutter get_storage 实例冲突
我正在为我的 Flutter 应用程序使用 GetX 和 get_storage。我的应用在 firebase_messaging 中按预期工作。
当应用程序处于后台时,我使用 get_storage 来保存当前消息,在尝试阅读消息列表的同时恢复(点击消息)时与进入后台之前相同。
重现步骤
- 打开应用
- 加载服务(包括 FCM)
- 转到前台
- 发送/接收消息保存到storage Key(可以看到storage 有消息)
- 轻点,恢复应用程序存储密钥列表看起来像以前一样 后台
我假设我错过了一些反映存储变化的操作。我正手道歉,因为我真的不知道如何使代码尽可能可读。
主要
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await ServicesSer().dependencies();
runApp(
GetMaterialApp(
title: "Application",initialRoute: AppPages.INITIAL,// showPerformanceOverlay: true,locale: TranslationService.locale,fallbackLocale: TranslationService.fallbackLocale,translations: TranslationService(),theme: theme.light,darkTheme: theme.dark,themeMode: await Get.find<StorageCtrl>().getSetting(
settingKey: 'THEME',settingValue: 'light',) ==
'light'
? ThemeMode.light
: ThemeMode.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);
}
}
FirebaseMessageSer
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 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',);
///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');
}
}
通知Ctrl
我知道在使用存储时有很多异步,正在测试这是否可能有什么关系
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,);
}
我应该使用 Fenix 来重新创建 storageCtrl 吗?希望有更多经验的人可以指出我遗漏了什么,或者告诉我这是否是默认行为。
提前致谢
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。