Flutter:测试期间的计时器问题

Posted

技术标签:

【中文标题】Flutter:测试期间的计时器问题【英文标题】:Flutter: Timer Issue During Testing 【发布时间】:2018-10-01 20:03:23 【问题描述】:

我的StatelessWidget 之一中有一个定期计时器。无需过多介绍,这里有一段生成计时器的代码:

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));

    . . .

当我尝试将应用程序的起点输入到 flutter test 时,我收到以下错误消息:

══╡ 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?如果没有,我该如何缓解这个错误?

【问题讨论】:

【参考方案1】:

问题是创建 Timer 会创建一个必须释放的资源,因此您的小部件实际上是有状态的,而不是无状态的。具体来说,build 方法可以每秒调用 60 次(如果平台是 120fps,则可以调用更多)。任何更少都只是一种优化。

您的代码中有一个非常严重的错误 - build 方法在每次调用时都会创建一个新的 Timer。而且由于您的计时器永远不会被取消,因此您可能会将数百甚至数千个事件发送到您的商店。

为了避免这种情况,框架有一个State 类,具有initStatedispose 生命周期。该框架承诺,如果它重建您的小部件,它不会多次调用initState,并且始终会调用dispose。这允许您创建一个 Timer 并在后续调用 build 时重复使用它。

例如,您可以将大部分逻辑移至如下所示的状态。将 refreshRate 保留在小部件上,您甚至可以使用 didUpdateWidget 生命周期取消和更新计时器。

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) 
    ...
  

【讨论】:

谢谢,有道理 我收到此错误类型 'Future' 不是类型 'Timer' 的子类型 _timer = Timer.periodic(Duration(seconds: 1), (Timer t) => _getTime());谢谢...

以上是关于Flutter:测试期间的计时器问题的主要内容,如果未能解决你的问题,请参考以下文章

Flutter:当倒数计时器达到 0 时执行动作

Flutter 中的倒数计时器日期和时间格式

滚动 UITableView 期间计时器将重置并停止运行

Flutter:显示分钟和秒的倒数计时器

计时器在长事件期间不启动

如何创建在使用 AnimationController 创建的倒数计时器期间发出的警报?