未处理的异常:在 dispose() 之后调用 setState():在 flutter 中

问题描述 投票:0回答:2

我正在尝试使用

setState
更改变量的值,但它给了我这个错误

Unhandled Exception: setState() called after dispose(): _SplashState#27d6e(lifecycle state: defunct, not mounted, ticker inactive)
E/flutter (12289): 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 (12289): 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 (12289): 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().

由于上述错误,我的屏幕上没有收到通知。

initState
函数中,我正在获取通知和
firebase token
并将值存储到
sharedPreference
。我希望将特定值存储在变量中,以便我可以在点击通知时访问其他屏幕上的更新值。

这是我的代码

class Splash extends StatefulWidget {
  const Splash({Key? key}) : super(key: key);
  @override
  _SplashState createState() => _SplashState();
}

class _SplashState extends State<Splash> with SingleTickerProviderStateMixin {
  late AnimationController controller;
  late Animation heartbeatAnimation;

@override
  void initState() {
    super.initState();
 controller = AnimationController(
        vsync: this, duration: const Duration(milliseconds: 500));
    heartbeatAnimation =
        Tween<double>(begin: 100.0, end: 250.0).animate(controller);
    controller.forward().whenComplete(() {
      controller.reverse();
    });


    Future.delayed(const Duration(seconds: 3), () async {
      FirebaseMessaging.onMessage.listen((RemoteMessage message) {
        print("onMessage Clicked!");
       
        String getId = message.data["id"];
        print("ride id get:    ${message.data["id"]}");
        if (mounted) {     
          setState(() {
            bookedRideId = int.parse(getId);   //this line is not wwrking, error points here
          });
        }
        RemoteNotification? notification = message.notification;
        AndroidNotification? android = message.notification?.android;
        if (notification != null && android != null) {
          flutterLocalNotificationsPlugin.show(
              notification.hashCode,
              notification.title,
              notification.body,
              NotificationDetails(
                android: AndroidNotificationDetails(
                  channel.id,
                  channel.name,
                  icon: android.smallIcon,
                ),
              ));
        }
      });
    
      getToken();

      FirebaseMessaging.onBackgroundMessage(
          _firebaseMessagingBackgroundHandler);

      // assign channel (required after android 8)
      await flutterLocalNotificationsPlugin
          .resolvePlatformSpecificImplementation<
              AndroidFlutterLocalNotificationsPlugin>()
          ?.createNotificationChannel(channel);

      // initialize notification for android
      var initialzationSettingsAndroid =
          AndroidInitializationSettings('@mipmap/ic_launcher');
      var initializationSettings =
          InitializationSettings(android: initialzationSettingsAndroid);
      flutterLocalNotificationsPlugin.initialize(initializationSettings);

      final NotificationAppLaunchDetails? notificationAppLaunchDetails =
          await flutterLocalNotificationsPlugin
              .getNotificationAppLaunchDetails();

      
      payload = notificationAppLaunchDetails!.payload;
      if (payload != null) {
        routeToGo = '/second';
        navigatorKey.currentState?.pushNamed('/second');
      }

      await flutterLocalNotificationsPlugin.initialize(initializationSettings,
          onSelectNotification: selectNotification);

      FirebaseMessaging.onMessageOpenedApp
          .listen((RemoteMessage message) async {
        print(message.notification!.body != null);
        if (message.notification!.body != null) {
          print("=======================rideid=====================");
          print(rideId);
          navigatorKey.currentState?.pushNamed('/second');
        }
      });

     

      SharedPreferences prefs = await SharedPreferences.getInstance();
      
      emailAddress = prefs.getString('email').toString();
      token = prefs.getString('token').toString();
      emailAddress == "null" && token == "null"
          ? Navigator.of(context).pushAndRemoveUntil(
              MaterialPageRoute(builder: (context) => const PreLogin()),
              (route) => false)
          : role == "driver"
              ? Navigator.of(context).pushAndRemoveUntil(
                  MaterialPageRoute(builder: (context) => DriverHome()),
                  (route) => false)
              : Navigator.of(context).pushAndRemoveUntil(
                  MaterialPageRoute(builder: (context) => const UserHome()),
                  (route) => false);
    });

   
  }

  @override
  void dispose() {
    controller.dispose();

    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return SafeArea(
      child: Scaffold(
          resizeToAvoidBottomInset: false,
          body: Container(
            decoration: const BoxDecoration(
              image: DecorationImage(
                image: AssetImage(splashBgImage),
                fit: BoxFit.fill,
              ),
            ),
            child: const Logo(),
          )),
    );
  }
}

请帮我解决这个问题。

flutter setstate dispose
2个回答
1
投票

你的

initState()
方法包含太多复杂的逻辑代码,需要重新格式化。

出现具体错误

setState() called after dispose()
是因为应用程序在调用当前页面的
setState()
方法之前已切换到另一个页面。

结合上面的代码,此代码片段将应用程序更改为另一个页面


      SharedPreferences prefs = await SharedPreferences.getInstance();

      emailAddress = prefs.getString('email').toString();
      token = prefs.getString('token').toString();
      emailAddress == "null" && token == "null"
          ? Navigator.of(context).pushAndRemoveUntil(
              MaterialPageRoute(builder: (context) => const PreLogin()),
              (route) => false)
          : role == "driver"
              ? Navigator.of(context).pushAndRemoveUntil(
                  MaterialPageRoute(builder: (context) => DriverHome()),
                  (route) => false)
              : Navigator.of(context).pushAndRemoveUntil(
                  MaterialPageRoute(builder: (context) => const UserHome()),
                  (route) => false);

在此代码片段之前

    Future.delayed(const Duration(seconds: 3), () async {
      FirebaseMessaging.onMessage.listen((RemoteMessage message) {
        print("onMessage Clicked!");

        String getId = message.data["id"];
        print("ride id get:    ${message.data["id"]}");
        if (mounted) {
          setState(() {
            bookedRideId =
                int.parse(getId); //this line is not wwrking, error points here
          });
        }
// ..

调用

setState()
方法。


0
投票

如果您想

setState({})
匿名,就像来自提供者的广播流侦听器回调一样,您必须等待您的小部件被安装,但需要一段时间

if(mounted){// your  code }
不足以实现这一目的,因此会导致内存泄漏问题。解决方案是创建一个异步函数来运行代码并从那里设置状态。必须始终遵守小部件的生命周期。任何对另一个小部件中的状态状态的匿名请求都会等到该小部件安装完毕,因此您必须延迟 setState({}) 几秒钟并检查小部件是否已安装,然后设置状态。假设您使用提供程序向流订阅设置消息以设置某种状态,假设未来,您的代码将如下所示

import 'package:flutter/material.dart';

class MyWidget extends StatefulWidget {
  const MyWidget({super.key});

  @override
  State<MyWidget> createState() => _MyWidgetState();
}

class _MyWidgetState extends State<MyWidget> {
 late  Future<demo> demoFuture;
   late StreamSubscription uiSubscription;
  @override
  void initState() {

    // TODO: implement initState
    super.initState();
    demoFuture = getDemoFuture();
       final applicationBloc =
        Provider.of<MyDemoBloc>(context, listen: false);
    uiSubscription = applicationBloc.uiCommunication.stream
        .asBroadcastStream()
        .listen((message) async {
updateMyFuture();

        });
  }

  void updateMyFuture(){
    /// your code
       Future.delayed(const Duration(seconds: 2), () async {
           setState(() {
              demoFuture = getDemoFuture();
           });
       });
  }
  @override
  Widget build(BuildContext context) {
    return const Placeholder();
  }
}
© www.soinside.com 2019 - 2024. All rights reserved.