Flutter:测试期间的计时器问题 [英] Flutter: Timer Issue During Testing

查看:417
本文介绍了Flutter:测试期间的计时器问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆