Я пытаюсь получать уведомления в своем приложении флаттера, используя Firebase Messaging, чтобы отображать их в приложении, но я продолжаю получать сообщение об ошибке:
/FLTFireMsgReceiver( 6823): broadcast received for message
E/flutter ( 6823): [ERROR:flutter/lib/ui/ui_dart_state.cc(209)] Unhandled Exception: setState() called after dispose(): _TipsState#aa4df(lifecycle state: defunct, not mounted)
E/flutter ( 6823): This error happens if you call setState() on a State object for a widget that no longer appears in the widget tree (e.g., whose parent widget no longer includes the widget in its build). This error can occur when code calls setState() from a timer or an animation callback.
E/flutter ( 6823): The preferred solution is to cancel the timer or stop listening to the animation in the dispose() callback. Another solution is to check the "mounted" property of this object before calling setState() to ensure the object is still in the tree.
E/flutter ( 6823): This error might indicate a memory leak if setState() is being called because another object is retaining a reference to this State object after it has been removed from the tree. To avoid memory leaks, consider breaking the reference to this object during dispose().
E/flutter ( 6823): #0 State.setState.<anonymous closure> (package:flutter/src/widgets/framework.dart:1085:9)
E/flutter ( 6823): #1 State.setState (package:flutter/src/widgets/framework.dart:1120:6)
E/flutter ( 6823): #2 _TipsState.getNotification.<anonymous closure> (package:stock_baba/Screens/Tips.dart:38:9)
E/flutter ( 6823): #3 _rootRunUnary (dart:async/zone.dart:1434:47)
E/flutter ( 6823): #4 _CustomZone.runUnary (dart:async/zone.dart:1335:19)
E/flutter ( 6823): #5 _CustomZone.runUnaryGuarded (dart:async/zone.dart:1244:7)
E/flutter ( 6823): #6 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:341:11)
E/flutter ( 6823): #7 _DelayedData.perform (dart:async/stream_impl.dart:591:14)
E/flutter ( 6823): #8 _StreamImplEvents.handleNext (dart:async/stream_impl.dart:706:11)
E/flutter ( 6823): #9 _PendingEvents.schedule.<anonymous closure> (dart:async/stream_impl.dart:663:7)
E/flutter ( 6823): #10 _rootRun (dart:async/zone.dart:1418:47)
E/flutter ( 6823): #11 _CustomZone.run (dart:async/zone.dart:1328:19)
E/flutter ( 6823): #12 _CustomZone.runGuarded (dart:async/zone.dart:1236:7)
E/flutter ( 6823): #13 _CustomZone.bindCallbackGuarded.<anonymous closure> (dart:async/zone.dart:1276:23)
E/flutter ( 6823): #14 _rootRun (dart:async/zone.dart:1426:13)
E/flutter ( 6823): #15 _CustomZone.run (dart:async/zone.dart:1328:19)
E/flutter ( 6823): #16 _CustomZone.runGuarded (dart:async/zone.dart:1236:7)
E/flutter ( 6823): #17 _CustomZone.bindCallbackGuarded.<anonymous closure> (dart:async/zone.dart:1276:23)
E/flutter ( 6823): #18 _microtaskLoop (dart:async/schedule_microtask.dart:40:21)
E/flutter ( 6823): #19 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49:5)
Класс PushNotification — это простой класс со строковыми полями title, body, dataTitle и dataBody. Мой код выглядит следующим образом:
class _TipsState extends State<Tips> {
final FirebaseMessaging _firebaseMessaging = FirebaseMessaging.instance;
final List<PushNotification> messages = [];
PushNotification? _notificationInfo;
@override
void initState() {
getNotification();
super.initState();
}
void getNotification() async {
NotificationSettings settings =
await _firebaseMessaging.requestPermission();
if (settings.authorizationStatus == AuthorizationStatus.authorized) {
print("Permission granted!");
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
PushNotification notification = PushNotification(
title: message.notification?.title,
body: message.notification?.body,
dataTitle: message.data['title'],
dataBody: message.data['body']);
setState(() {
_notificationInfo = notification;
});
if (notification != null) {
showSimpleNotification(Text(_notificationInfo!.title!),
duration: Duration(seconds: 2),
subtitle: Text(_notificationInfo!.body!));
}
print(notification);
print(message.data);
});
} else {
print("Permission declined!");
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: messages.isEmpty
? Container()
: ListView(
children: [Text(messages[0].title!)],
),
);
}
}
Я попытался обернуть setState() с помощью mount(), но это не сработало.
Как я могу решить эту проблему и отображать входящие уведомления в своем приложении?
Я думаю, вам не нужно setstate, чтобы показать уведомление
Отмените Stream
после его утилизации
Создать переменную StreamSubscription
StreamSubscription messagingSubscription;
Назначьте переменную вашему listen
....
messagingSubscription = FirebaseMessaging.onMessage.listen((RemoteMessage message) {
Dispose
твой StreamSubscription
@override
void dispose() {
messagingSubscription?.cancel();
super.dispose();
}
Это сработало! Как я могу отобразить его в своем приложении?
вы можете слушать FirebaseMessaging
в личном кабинете/на домашней странице
вот мой код, и он работает. Скопируйте код, создайте класс дротика и вставьте его. ваше уведомление начинает работать
используйте там плагины
firebase_core: ^1.11.0 firebase_messaging: ^11.2.5 flutter_local_notifications: ^9.2.0
import 'dart:convert';
import 'dart:math';
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:vcare/firebase_options.dart';
class NotificationHelper {
NotificationDetails get _ongoing {
const androidChannelSpecifics = AndroidNotificationDetails(
'customer-channel-id',
'customer-channel-name',
importance: Importance.max,
priority: Priority.high,
ongoing: false,
autoCancel: true,
);
const iOSChannelSpecifics = IOSNotificationDetails();
return const NotificationDetails(android: androidChannelSpecifics, iOS: iOSChannelSpecifics);
}
// Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
// If you're going to use other Firebase services in the background, such as Firestore,
// make sure you call `initializeApp` before using other Firebase services.
// await initFirebase();
// }
configure() async {
await initFirebase();
FirebaseMessaging messaging = FirebaseMessaging.instance;
await requestPermission(messaging);
final String? token = await messaging.getToken();
// FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
final notification = await setupLocalNotification();
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
showNotification(
notification,
title: message.notification?.title,
body: message.notification?.body,
payload: message.data,
type: _ongoing,
);
});
return token;
}
Future<void> requestPermission(FirebaseMessaging messaging) async {
await messaging.requestPermission(
alert: true,
announcement: false,
badge: true,
carPlay: false,
criticalAlert: false,
provisional: false,
sound: true,
);
}
Future<void> initFirebase() async {
await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
);
}
setupLocalNotification() async {
const AndroidInitializationSettings initializationSettingsAndroid = AndroidInitializationSettings(
'notification_icon',
);
final IOSInitializationSettings initializationSettingsIOS = IOSInitializationSettings(
onDidReceiveLocalNotification: (int id, String? title, String? body, String? payload) {},
);
final InitializationSettings initializationSettings = InitializationSettings(
android: initializationSettingsAndroid,
iOS: initializationSettingsIOS,
);
var notification = FlutterLocalNotificationsPlugin();
await notification.initialize(initializationSettings, onSelectNotification: (_) {});
return notification;
}
showNotification(FlutterLocalNotificationsPlugin notifications,
{required String? title, required String? body, required NotificationDetails type, required payload}) {
notifications.show(Random().nextInt(100), title, body, type, payload: json.encode(payload ?? {}));
}
}
а затем вызовите этот класс в файле main.dart вот код
WidgetsFlutterBinding.ensureInitialized();
String? token = await NotificationHelper().configure();
_storeFCMToken(token);
print("deviceToken $token");
если вы обнаружите какие-либо проблемы, пожалуйста, дайте мне знать. если вы обнаружите, что этот код помогает вам, пожалуйста, отметьте мой ответ как принятый
Что такое _storeFCMToken (токен); должен сделать?
это функция для хранения токена в локальной базе данных
так что мне придется создать функцию, верно?
нет не надо. просто удалите это
Я должен вызвать виджет на экране, в котором я должен показать уведомление или файл main.dart?
в основном файле ..и в основном методе после этой строки WidgetsFlutterBinding.ensureInitialized();
Как отобразить данные в уведомлении на моем экране?
есть два типа локальных уведомлений или вы отправляете уведомление из Firebase .. что вы хотите ..? локальное уведомление похоже на то, когда вы нажимаете кнопку .. экран показывает уведомление ..?
Я отправляю уведомления из Firebase, и мне нужно показать их на экране
работа над кодом завершена. вы настроили уведомление .. ? если не посмотреть какой-нибудь туториал
Я могу получать уведомления от FCM, но мне также нужно показать сообщение на экране. Что я использую для этого?
вы получаете уведомление о вашем приложении .. ?
да, я получаю их на своем эмуляторе
Я думаю, что вы должны прослушивать сообщения за пределами виджета и обновлять дерево виджетов, когда приходит уведомление.