Необработанное исключение: setState() вызывается после dispose()

Я пытаюсь получать уведомления в своем приложении флаттера, используя 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(), но это не сработало.

Как я могу решить эту проблему и отображать входящие уведомления в своем приложении?

Я думаю, что вы должны прослушивать сообщения за пределами виджета и обновлять дерево виджетов, когда приходит уведомление.

Antoniossss 22.03.2022 10:23

Я думаю, вам не нужно setstate, чтобы показать уведомление

benten 22.03.2022 11:47
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
2
77
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Отмените Stream после его утилизации

Создать переменную StreamSubscription

  StreamSubscription messagingSubscription;

Назначьте переменную вашему listen

....
messagingSubscription = FirebaseMessaging.onMessage.listen((RemoteMessage message) {

Dispose твой StreamSubscription

  @override
  void dispose() {
    messagingSubscription?.cancel();
    super.dispose();
  }

Это сработало! Как я могу отобразить его в своем приложении?

Abhi 22.03.2022 12:20

вы можете слушать FirebaseMessaging в личном кабинете/на домашней странице

BIS Tech 23.03.2022 06:14
Ответ принят как подходящий

вот мой код, и он работает. Скопируйте код, создайте класс дротика и вставьте его. ваше уведомление начинает работать

используйте там плагины

  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 (токен); должен сделать?

Abhi 22.03.2022 12:41

это функция для хранения токена в локальной базе данных

benten 22.03.2022 12:44

так что мне придется создать функцию, верно?

Abhi 22.03.2022 12:57

нет не надо. просто удалите это

benten 22.03.2022 13:01

Я должен вызвать виджет на экране, в котором я должен показать уведомление или файл main.dart?

Abhi 22.03.2022 13:07

в основном файле ..и в основном методе после этой строки WidgetsFlutterBinding.ensureInitialized();

benten 22.03.2022 13:13

Как отобразить данные в уведомлении на моем экране?

Abhi 22.03.2022 13:40

есть два типа локальных уведомлений или вы отправляете уведомление из Firebase .. что вы хотите ..? локальное уведомление похоже на то, когда вы нажимаете кнопку .. экран показывает уведомление ..?

benten 22.03.2022 13:47

Я отправляю уведомления из Firebase, и мне нужно показать их на экране

Abhi 22.03.2022 13:57

работа над кодом завершена. вы настроили уведомление .. ? если не посмотреть какой-нибудь туториал

benten 22.03.2022 14:04

Я могу получать уведомления от FCM, но мне также нужно показать сообщение на экране. Что я использую для этого?

Abhi 22.03.2022 16:12

вы получаете уведомление о вашем приложении .. ?

benten 23.03.2022 08:59

да, я получаю их на своем эмуляторе

Abhi 23.03.2022 09:51

Другие вопросы по теме