Timer.periodic 无法与提供商一起正常工作

Timer.periodic does not work correctly with provider

我正在尝试在扩展 class ChangeNotifier 的 class 中使用 class Timer 的方法 periodic (包 Provider)使我的变量 time 每秒减少。

如果我不添加重绘所有占据 time 属性 的小部件的 NotifyListeners 方法,这将正常工作,例如:

class PriceProvider extends ChangeNotifier{
  int _time = 60;

  int get time{
    return _time;
  }

  void chronometer(){//method which activate the timer

    Timer _timer = Timer.periodic(const Duration(seconds: 1), (Timer timer){
      print(DateTime.now());//I print the date so you can see how often the code is executed
      
      _time += -1;//decrease time

      if(_time == 0){
        _time = 60;
      } 

      // notifyListeners(); 
    });
  } 

}

控制台输出(每秒正确运行):

另一方面,如果我取消注释 NotifyListeners 方法,代码开始以指数方式每秒执行越来越多的次数(例如,首先执行一次,然后执行两次,然后执行 5 次,然后执行 9 次,然后很快):

这是我调用方法 chronometer:

的代码
class PriceWithClock extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    PriceProvider priceProvider = Provider.of<PriceProvider>(context);
    priceProvider.chronometer();
    return CircularPercentIndicator(
      radius: 100.0,
      lineWidth: 5.0,
      percent: 1-priceProvider.time/60,
      center: Text("00:${priceProvider.time}"),
     ),
    );
  }
}

您不应该将 priceProvider.chronometer(); 放在构建方法中,因为它将在每个 PriceWithClock 小部件构建时执行。在你的情况下,它会每秒发生一次。

您可以做的是创建一个有状态的小部件并在 initState() 方法中触发计时器:

class PriceWithClock extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => _PriceWithClockState();
}

class _PriceWithClockState extends State<PriceWithClock> {
  @override
  void initState() {
    super.initState();

    context.read<PriceProvider>().chronometer();
  }

  @override
  Widget build(BuildContext context) {
    ...
  }
}

至于 build 方法,您可以使用 context.watch Provider 扩展方法来监听更新后的 time 值:

class _PriceWithClockState extends State<PriceWithClock> {
  ...

  @override
  Widget build(BuildContext context) {
    final time = context.watch<PriceProvider>().time;
    
    return CircularPercentIndicator(
      radius: 100.0,
      lineWidth: 5.0,
      percent: 1 - time / 60,
      center: Text("00:$time"),
    );
  }
}

最终结果如下所示:

class PriceWithClock extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => _PriceWithClockState();
}

class _PriceWithClockState extends State<PriceWithClock> {
  @override
  void initState() {
    super.initState();

    context.read<PriceProvider>().chronometer();
  }

  @override
  Widget build(BuildContext context) {
    final time = context.watch<PriceProvider>().time;
    
    return CircularPercentIndicator(
      radius: 100.0,
      lineWidth: 5.0,
      percent: 1 - time / 60,
      center: Text("00:$time"),
    );
  }
}