flutter 在dispose()之后调用setState()

b91juud3  于 2023-02-05  发布在  Flutter
关注(0)|答案(9)|浏览(213)

当我单击凸起的按钮时,时间选择器显示出来。现在,如果我等待5秒钟,例如,然后确认时间,将出现以下错误:在dispose()之后调用setState()
我真的在控制台看到flutter是如何更新父控件的,但是为什么呢?我什么也没做-我只是等了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();
      }
    );
  }
}
j13ufse2

j13ufse21#

在调用setState()之前,只需检查小部件的state类的布尔属性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);
    }
  }
}
krugob8w

krugob8w2#

如果这是Future在小部件已被释放时完成的预期行为,则可以使用

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

bvuwiixz3#

只在setState()前写一行

if (!mounted) return;

然后

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

nfeuvbwi4#

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

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

右侧代码:

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

wmvff8tz5#

要防止发生错误,可以使用State类的mounted属性来确保在设置小部件的状态之前已挂载小部件:

// First Update data 

if (!mounted) { 
      return;
 }
setState(() { }
sd2nnvve

sd2nnvve6#

试试这个

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

wf82jlnq7#

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> {
  ....
}
dbf7pr2w

dbf7pr2w8#

当我错误地在变量之前调用super.initState时,我遇到了这个错误。

@override
void initState() {
super.initState();
   bloc = MainBloc();
  }

应固定为

@override
void initState() {
   bloc = MainBloc();
super.initState(); 
  }
isr3a4wc

isr3a4wc9#

当您在有状态小部件中执行长时间异步操作时,可能会在操作完成之前关闭/处置该小部件,此时可能会出现此问题。
Dart中的future不是抢占式的,因此唯一的方法是在调用setState之前检查是否挂载了一个小部件。
如果您有很多具有异步特性的小部件,那么添加大量的if (mounted)检查是非常繁琐的,扩展方法可能会很有用

extension FlutterStateExt<T extends StatefulWidget> on State<T> {
  void setStateIfMounted(VoidCallback fn) {
    if (mounted) {
      // ignore: invalid_use_of_protected_member
      setState(fn);
    }
  }
}

相关问题