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

发布于 2025-01-15 04:03:21 字数 1621 浏览 2 评论 0 原文

我正在尝试在扩展了类 ChangeNotifier (包 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(); 
    });
  } 

}

控制台输出(每秒正确运行): 萨利达consola

另一方面,如果我取消注释 NotifyListeners 方法,代码就会开始以指数方式每秒执行越来越多的次数(例如,首先执行一次,然后执行两次,然后是 5,然后是 9,依此类推): 萨利达consola

这是我调用方法 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}"),
     ),
    );
  }
}

I am trying to use the method periodic of the class Timer inside a class which extends of the class ChangeNotifier (of the package Provider) making my variable time decrease every second.

This works correctly if I don't add the NotifyListeners method which redraws all the widgets that occupy the time property, like:

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

}

Console output (runs every second correctly):
Salida por consola

On the other hand, if I uncomment the NotifyListeners method, the code starts executing more and more times per second exponentially (for example, first it executes once, then twice, then 5, then 9 and so on):
Salida por consola

Here is the code where I call the method 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}"),
     ),
    );
  }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

极度宠爱 2025-01-22 04:03:21

您不应将 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"),
    );
  }
}

You should not put the priceProvider.chronometer(); inside the build method since it will be executed on every PriceWithClock widget build. And in your case, it would happen every second.

What you can do, is create a Stateful widget and trigger the chronometer inside the initState() method:

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

As for the build method, you could use the context.watch Provider extension method to listen to the updated time value:

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"),
    );
  }
}

The final result looks like this:

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"),
    );
  }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文