androidflutterdartuser-interfacetimer

Why this timer doesn't stop?


I have made a timer in a Flutter app, and I want the timer to stop when it reaches 1 second, but it doesn't. I don't know where is the problem.

Here is the code and the emulator running: enter image description here

And here is the code:

class _MyHomeState extends State<MyHome> {
  double progress = 0;
  void startTimer() {
    Timer.periodic(const Duration(seconds: 1), (timer) {
      setState(() {
        if (progress == 1) {
          timer.cancel();
        } else {
          progress += 0.1;
        }
      });
    });
  }

  @override
  Widget build(BuildContext context) {
    return Center(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          Stack(
            alignment: Alignment.center,
            children: [
              Text(progress.toStringAsFixed(1)),
              SizedBox(
                height: 300,
                width: 300,
                child: CircularProgressIndicator(
                  value: progress,
                  color: Colors.deepOrange,
                ),
              )
            ],
          ),
          const SizedBox(
            height: 50,
          ),
          ElevatedButton(
              onPressed: () {
                setState(() {
                  progress = 0;
                  startTimer();
                });
              },
              child: const Text('Start'))
        ],
      ),
    );
  }
}

Solution

  • It's because of floating point error. In software development decimals can't be used in calculations with 100% accuracy. You can't guarantee that 0.1 + 0.1 = 0.2. The problem here is that progress never will equal 1. If you print progress in your else branch of the timer you will see that it shows:

    0.1
    0.2
    0.30000000000000004
    0.4
    0.5
    0.6
    0.7
    0.7999999999999999
    0.8999999999999999
    0.9999999999999999
    1.0999999999999999
    1.2
    1.3
    

    To solve it simply don't check for one but check if it's higher than 0.99 for example so like

            if (progress > 0.99) {
              timer.cancel();
            } else {
              progress += 0.1;
            }