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

Luc*_*mic 0 dart flutter flutter-provider

我试图在一个类中使用periodic该类的方法Timer,该类扩展了该类ChangeNotifier(包Provider),使我的变量time每秒都在减少。

如果我不添加NotifyListeners重绘占用该time属性的所有小部件的方法,则此方法可以正常工作,例如:

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

}
Run Code Online (Sandbox Code Playgroud)

控制台输出(每秒正确运行): 萨利达·波尔·康索拉

另一方面,如果我取消对该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}"),
     ),
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

mko*_*lys 5

您不应该将其放入priceProvider.chronometer();构建方法中,因为它将在每个小部件构建时执行PriceWithClock。就你而言,这种情况每秒都会发生。

您可以做的是创建一个 Stateful 小部件并在方法内触发计时器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) {
    ...
  }
}
Run Code Online (Sandbox Code Playgroud)

至于build方法,您可以使用context.watchProvider 扩展方法来监听更新的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"),
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

最终结果如下所示:

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"),
    );
  }
}
Run Code Online (Sandbox Code Playgroud)