在 dispose() 之后调用 setState()
Posted
技术标签:
【中文标题】在 dispose() 之后调用 setState()【英文标题】:setState() called after dispose() 【发布时间】:2018-08-26 15:56:39 【问题描述】:当我点击凸起的按钮时,时间选择器就会出现。现在,例如,如果我等待 5 秒,然后确认时间,则会出现此错误: setState() 在 dispose() 之后调用
我确实在控制台中看到了颤振是如何更新父小部件的,但是为什么呢?我什么都不做——我只等5秒?! 下面的示例将在普通项目中工作,但是在我的项目中它更复杂,因为在我等待时 Flutter 正在更新状态......我做错了什么?有没有人猜到 Flutter 在我更复杂的项目中而不是在简单项目中随机更新的原因是什么?
[更新]
我再次查看它,发现它正在从我的TabBar
和TabBarView
所在的级别更新。
它是否必须与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" - 是的,我认为这会导致您的小部件被重建。 【参考方案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
而不是使用 Stateclass ExampleStatefulWidget extends StatefulWidget
const ExampleStatefulWidget(Key key) : super(key: key);
@override
_ExampleStatefulWidgetState createState() => _ExampleStatefulWidgetState();
class _ExampleStatefulWidgetState extends MountedState<ExampleStatefulWidget>
....
【讨论】:
以上是关于在 dispose() 之后调用 setState()的主要内容,如果未能解决你的问题,请参考以下文章
为啥在 setState 之后调用 getDerivedStateFromProps?
即使在调用 setState 之后,React.js 子状态也不会重新渲染?