Flutter:测试期间的计时器问题 [英] Flutter: Timer Issue During Testing
问题描述
我的 StatelessWidget
之一有一个定期计时器。无需赘述,下面是一段生成计时器的代码片段:
I have a periodic timer in one of my StatelessWidget
's. Without going too much into detail, here is a snippet of code producing a timer:
class AnniversaryHomePage extends StatelessWidget {
. . .
void _updateDisplayTime(StoreInheritedWidget inheritedWidget) {
String anniversaryString = inheritedWidget.prefs.getString('anniversaryDate');
inheritedWidget.store.dispatch(DateTime.parse(anniversaryString));
}
/// Widget Methods
@override
Widget build(BuildContext context) {
final inheritedWidget = StoreInheritedWidget.of(context);
new Timer.periodic(this.refreshRate, (Timer timer) => _updateDisplayTime(inheritedWidget));
. . .
}
当我尝试将应用程序的起点插入时颤振测试
,我收到以下错误消息:
When I try pumping my the application's starting point into flutter test
, I get the following error message:
══╡ EXCEPTION CAUGHT BY FLUTTER TEST FRAMEWORK ╞════════════════════════════════════════════════════
The following assertion was thrown running a test:
A periodic Timer is still running even after the widget tree was disposed.
'package:flutter_test/src/binding.dart': Failed assertion: line 668 pos 7:
'_fakeAsync.periodicTimerCount == 0'
问题是,我是否错误地使用了 Timer.periodic
?如果不是,我该如何缓解该错误?
The question is, am I using my Timer.periodic
incorrectly? If not, how do I mitigate this error?
推荐答案
问题是创建一个Timer会创建必须处置的资源,因此,您的小部件实际上是有状态的,而不是无状态的。具体来说, build
方法可能每秒调用60次(如果平台为120fps,则调用更多次)。少就是优化。
The issue is that creating a Timer creates a resource which must be disposed, and therefore your widget is actually Stateful and not stateless. Specifically, the build
method may be called 60 times a second (or more if the platform is 120fps). Any less is just an optimization.
您的代码中有一个非常关键的错误- build
方法每次创建一个新的Timer叫。而且由于您的计时器永远都不会取消,因此您可以将数百甚至数千个事件调度到商店。
You have a very critical bug in your code - the build
method is creating a new Timer every time it is called. And since your timers are never cancelled, you could have hundreds or potentially thousands of events dispatched to your store.
为避免此类情况,该框架具有 State
类和 initState
和处置
生命周期。该框架承诺,如果重新构建窗口小部件,它将不会多次调用 initState
,并且将始终调用 dispose
。这样,您就可以一次创建一个计时器,并在随后的 build
调用中重新使用它。
To avoid situations like this, the framework has a State
class, with an initState
and dispose
lifecycle. The framework promises that if it rebuilds your widget, it won't call initState
more than once and it will always call dispose
. This allows you to create a Timer once and reuse it on subsequent calls to build
.
例如,您可以将您的大部分逻辑移至该州,如下所示。将refreshRate保留在窗口小部件上,甚至可以使用 didUpdateWidget
生命周期。
For example, you can move most of your logic to the State like below. Leave the refreshRate on the widget, and you can even cancel and update your timer using the didUpdateWidget
lifecycle too.
class AnniversaryHomePage extends StatefulWidget {
@override
State createState() => new AnniversaryHomePageState();
}
class AnniversaryHomePageState extends State<AnniversaryHomePage> {
Timer _timer;
@override
void initState() {
_timer = new Timer.periodic(widget.refreshRate,
(Timer timer) => _updateDisplayTime(inheritedWidget));
super.initState();
}
@override
void dispose() {
_timer.cancel();
super.dispose();
}
@override
Widget build(BuildContext context) {
...
}
}
这篇关于Flutter:测试期间的计时器问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!