在构建异常期间调用的 setState() 或 markNeedsBuild() 阻止我执行回调
Posted
技术标签:
【中文标题】在构建异常期间调用的 setState() 或 markNeedsBuild() 阻止我执行回调【英文标题】:setState() or markNeedsBuild() called during build exception prevents me from executing callback 【发布时间】:2019-10-16 16:28:15 【问题描述】:一旦计时器在特定小部件中结束,我正在尝试执行回调函数,但我不断收到此异常:
I/flutter (16413):引发了另一个异常:在构建期间调用了 setState() 或 markNeedsBuild()。
所以我有一个名为 countdown
的小部件:
class Countdown extends StatefulWidget
final VoidCallback onCountdownExpire;
Countdown(this.onCountdownExpire);
@override
CountdownState createState() => CountdownState();
class CountdownState extends State<Countdown> with TickerProviderStateMixin
AnimationController controller;
String get timerString
Duration duration = controller.duration * controller.value;
return '$duration.inMinutes:$(duration.inSeconds % 60).toString()';
@override
void initState()
super.initState();
controller = AnimationController(
vsync: this,
duration: Duration(seconds: 2),
)..addStatusListener((AnimationStatus status)
if (status == AnimationStatus.completed)
widget.onCountdownExpire();
);
controller.reverse(from: 1.0);
...
...
... // omitted code
所以一旦动画完成就会调用回调函数:
class _QuizPageState extends State<QuizPage>
... // omitted code
@override
void initState()
... // omitted code
void onCountdownExpire()
setState(()
_topContentImage = AssetImage(questions[questionNum++].imagePath);
);
... // omitted code
我尝试关注solution,但它不起作用并给了我同样的例外:
void onCountdownExpire() =>
setState(()
_topContentImage = AssetImage(questions[questionNum++].imagePath);
);
我也试过了,但没用:
@override
void initState()
super.initState();
controller = AnimationController(
vsync: this,
duration: Duration(seconds: 2),
)..addStatusListener((AnimationStatus status) =>
(status == AnimationStatus.completed) ?
widget.onCountdownExpire():null
);
controller.reverse(from: 1.0);
【问题讨论】:
【参考方案1】:也许尝试包括 'dart:async':
import 'dart:async';
然后尝试将您对 onCountdownExpire
函数的调用封装在一个短暂的 Timer()
中:
...
Timer(
Duration(milliseconds:50),
()
if (status == AnimationStatus.completed)
widget.onCountdownExpire();
,
);
...
这将使setState()
发生在动画最后一帧的构建阶段之外。
该错误最有可能是因为 Countdown()
正在作为 QuizPage()
小部件重绘的一部分而被重绘。添加Timer()
将强制更新在build()
范围之外以异步方式进行,并且仍将获得相同的结果而不会出现错误。
【讨论】:
好的,我试过了,得到了这个异常,而不是I/flutter (16413): Another exception was thrown: RangeError (index): Invalid value: Not in range 0..1, inclusive: 2
您是否进行了完全重启?还是只是热重载?因为此更改发生在 initState() 方法中,所以您需要完全重新启动。此外,消息的截断错误消息(“另一个异常......”)通常意味着在该异常之前引发了先前的异常。了解该异常是什么有助于缩小问题范围。
好的,我想我知道为什么会抛出范围错误,因为questions
只有 2 个元素并且它正在调用 [2],这是错误的。发生这种情况的原因是,当动画开始时,它以某种方式“完成”了,因为我在调用 windget.onCountdownExpire()
之前插入了一个调试打印,它在动画开始时打印,而不是在动画结束时打印。
我完全重启了
好的,开始时状态已完成的原因:controller.reverse(from: 1.0);
。在我将其更改为controller.animateTo(1.0);
后,它在动画结束时完成。以上是关于在构建异常期间调用的 setState() 或 markNeedsBuild() 阻止我执行回调的主要内容,如果未能解决你的问题,请参考以下文章
Flutter - 在构建期间调用 setState() 或 markNeedsBuild()
在构建期间调用 setState() 或 markNeedsBuild() - Flutter
Flutter:在构建期间调用 setState() 或 markNeedsBuild()
在构建 CupertinoTabScaffold 期间调用 setState() 或 markNeedsBuild()