【问题标题】:setState() called after dispose()在 dispose() 之后调用 setState()
【发布时间】:2018-08-26 15:56:39
【问题描述】:

当我点击凸起的按钮时,时间选择器就会出现。现在,例如,如果我等待 5 秒,然后确认时间,则会出现此错误: setState() 在 dispose() 之后调用

我确实在控制台中看到了颤振是如何更新父小部件的,但是为什么呢?我什么都不做——我只等5秒?! 下面的示例将在普通项目中工作,但是在我的项目中它更复杂,因为在我等待时 Flutter 正在更新状态......我做错了什么?有没有人猜到 Flutter 在我更复杂的项目中而不是在简单项目中随机更新的原因是什么?

[更新] 我再次查看它,发现它正在从我的TabBarTabBarView 所在的级别更新。 它是否必须与TabBarView 所需的“with TickerProviderStateMixin”有关?会不会是导致应用定期随机刷新?

 class DateTimeButton extends State<DateTimeButtonWidget> {
  DateTime selectedDate = new DateTime.now();

  Future initTimePicker() async {
    final TimeOfDay picked = await showTimePicker(
      context: context,
      initialTime: new TimeOfDay(hour: selectedDate.hour, minute: selectedDate.minute),
    );

    if (picked != null) {
      setState(() {
        selectedDate = new DateTime(selectedDate.year, selectedDate.month, selectedDate.day, picked.hour, picked.minute);
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return new RaisedButton(
      child: new Text("${selectedDate.hour} ${selectedDate.minute}"),
      onPressed: () {
        initTimePicker();
      }
    );
  }
}

【问题讨论】:

  • "with TickerProviderStateMixin" - 是的,我认为这会导致您的小部件被重建。

标签: flutter


【解决方案1】:

在调用 setState() 之前,只需检查小部件状态类的布尔属性 mounted

if (this.mounted) {
  setState(() {
    // Your state change code goes here
  });
}

或者更干净的方法 在 StatelfulWidget 类中覆盖 setState 方法。

class DateTimeButton extends StatefulWidget {
  @override
  void setState(fn) {
    if(mounted) {
      super.setState(fn);
    }
  }
}

【讨论】:

  • 只是阻止设置状态,并没有解决无法设置状态的问题
  • @temirbek 我不确定您的用例是什么,该 if 条件的目的正是在未安装小部件后停止尝试设置状态,这意味着小部件不存在屏幕上小部件的层次结构。
  • 好的,我的用例是屏幕 A 调用屏幕 B 并等待结果。屏幕 B 返回结果,但到那时屏幕 A 重新创建,并且正在等待结果的旧屏幕被卸载。但我需要在 ScreenA 中使用从 ScreenB 返回的值设置状态
  • 在您的用例中,您必须确保 ScreenA 在 ScreenB 返回时具有相同的实例,检查 ScreenA 键是否相同,如果不能这样做,并且 ScreenA 必须重新创建新实例,那么你将不得不使用某种方式来实现状态管理,比如 ScopedModel、Bloc 或 FlutterRedux 等。
  • 为什么框架默认不做内部检查?有没有可以为已处理的小部件设置状态的情况?!
【解决方案2】:

如果在小部件已被处置时Future 完成是预期行为,您可以使用

if (mounted) {
  setState(() {
    selectedDate = new DateTime(selectedDate.year, selectedDate.month, selectedDate.day, picked.hour, picked.minute);
  });
}

【讨论】:

  • 我会推荐docs.flutter.io/flutter/widgets/State/mounted.html,而不是使用您自己的会员。
  • 谢谢伙计。这节省了我的一天(绝对是一周):D
  • @Gunter,我们如何在 super.dispose() 之前调用 setState;在 dispose() 函数中。它对我不起作用,并收到错误消息,例如 'package:flutter/src/widgets/framework.dart': Failed assertion: line 4263 pos 12: '_debugLifecycleState != _ElementLifecycle.defunct': is not true。我已经在使用 if (mounted) { setState(() {});请提出什么问题。非常感谢。
【解决方案3】:

setState()前写一行

 if (!mounted) return;

然后

setState(() {
      //Your code
    });

【讨论】:

    【解决方案4】:

    我遇到了同样的问题,我解决了更改initState() 上的超级构造函数调用顺序:

    错误代码:

    @override
      void initState() {
        foo_bar(); // in foo_bar i call setState();
        super.initState(); // state initialization after foo_bar()
      }
    

    正确的代码:

    @override
      void initState() {
        super.initState();
        foo_bar(); // first call super constructor then foo_bar that contains setState() call
      }
    

    【讨论】:

    • 这很有帮助,但我想知道为什么,我以相反的顺序将它放在另一个地方并且没有给我任何问题
    【解决方案5】:

    为了防止错误发生,可以利用State 类的mounted 属性来确保在设置它的状态之前挂载一个小部件:

    // First Update data 
    
    if (!mounted) { 
          return;
     }
    setState(() { }
    

    【讨论】:

    • 写答案时,请在代码中写几句话,不要只用一个词。
    【解决方案6】:

    试试这个

    Widget build(BuildContext context) {
        return new RaisedButton(
            child: new Text("${selectedDate.hour} ${selectedDate.minute}"),
            onPressed: () async {
                await initTimePicker();
            }
        );
    }
    

    【讨论】:

      【解决方案7】:
      class MountedState<T extends StatefulWidget> extends State<T> {
        @override
        Widget build(BuildContext context) {
          return null;
        }
      
        @override
        void setState(VoidCallback fn) {
          if (mounted) {
            super.setState(fn);
          }
        }
      }
      

      示例

      为了防止错误,使用 MountedState

      而不是使用 State
      class ExampleStatefulWidget extends StatefulWidget {
        const ExampleStatefulWidget({Key key}) : super(key: key);
      
        @override
        _ExampleStatefulWidgetState createState() => _ExampleStatefulWidgetState();
      }
      
      class _ExampleStatefulWidgetState extends MountedState<ExampleStatefulWidget> {
        ....
      }
      

      【讨论】:

        猜你喜欢
        • 2019-10-28
        • 2021-01-01
        • 2021-12-25
        • 2020-12-05
        • 2021-03-12
        • 2020-12-14
        • 2020-12-28
        • 1970-01-01
        • 2018-12-03
        相关资源
        最近更新 更多