title: Repeating Animation and Adjustments in Flutter
body: <p>I'm trying to clone the timer of the app I use when I workout: Strong. So far, I've managed to implement all the main features and animations (which aren't many). I know my code is messy and there's probably better ways to implement what I'm trying to do if there are any suggestions on that they're also appreciated. I'm having two problems with my application. 1. When the timer starts I get the following error:</p>
  
  <pre><code>flutter: ══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY 
  
  ╞═══════════════════════════════════════════════════════════
  flutter: The following NoSuchMethodError was thrown building Peinture(dirty, state: _PeintureState#82e34):
  flutter: The getter 'inMilliseconds' was called on null.
  flutter: Receiver: null
  flutter: Tried calling: inMilliseconds
  flutter:
  flutter: When the exception was thrown, this was the stack:
  flutter: #0      Object.noSuchMethod (dart:core/runtime/libobject_patch.dart:50:5)
  flutter: #1      _PeintureState.build (package:workout_timer/main.dart:241:72)
  flutter: #2      StatefulElement.build (package:flutter/src/widgets/framework.dart:3809:27)
  flutter: #3      ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3721:15)
  flutter: #4      Element.rebuild (package:flutter/src/widgets/framework.dart:3547:5)
  flutter: #5      StatefulElement.update (package:flutter/src/widgets/framework.dart:3878:5)
  flutter: #6      Element.updateChild (package:flutter/src/widgets/framework.dart:2742:15)
  flutter: #7      SingleChildRenderObjectElement.update (package:flutter/src/widgets/framework.dart:4867:14)
  flutter: #8      Element.updateChild (package:flutter/src/widgets/framework.dart:2742:15)
  flutter: #9      ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3732:16)
  flutter: #10     Element.rebuild (package:flutter/src/widgets/framework.dart:3547:5)
  flutter: #11     ProxyElement.update (package:flutter/src/widgets/framework.dart:3990:5)
  flutter: #12     Element.updateChild (package:flutter/src/widgets/framework.dart:2742:15)
  flutter: #13     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3732:16)
  flutter: #14     Element.rebuild (package:flutter/src/widgets/framework.dart:3547:5)
  flutter: #15     StatelessElement.update (package:flutter/src/widgets/framework.dart:3781:5)
  flutter: #16     Element.updateChild (package:flutter/src/widgets/framework.dart:2742:15)
  flutter: #17     RenderObjectElement.updateChildren (package:flutter/src/widgets/framework.dart:4585:32)
  flutter: #18     MultiChildRenderObjectElement.update (package:flutter/src/widgets/framework.dart:4975:17)
  flutter: #19     Element.updateChild (package:flutter/src/widgets/framework.dart:2742:15)
  flutter: #20     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3732:16)
  flutter: #21     Element.rebuild (package:flutter/src/widgets/framework.dart:3547:5)
  flutter: #22     ProxyElement.update (package:flutter/src/widgets/framework.dart:3990:5)
  flutter: #23     Element.updateChild (package:flutter/src/widgets/framework.dart:2742:15)
  flutter: #24     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3732:16)
  flutter: #25     Element.rebuild (package:flutter/src/widgets/framework.dart:3547:5)
  flutter: #26     ProxyElement.update (package:flutter/src/widgets/framework.dart:3990:5)
  flutter: #27     Element.updateChild (package:flutter/src/widgets/framework.dart:2742:15)
  flutter: #28     RenderObjectElement.updateChildren (package:flutter/src/widgets/framework.dart:4585:32)
  flutter: #29     MultiChildRenderObjectElement.update (package:flutter/src/widgets/framework.dart:4975:17)
  flutter: #30     Element.updateChild (package:flutter/src/widgets/framework.dart:2742:15)
  flutter: #31     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3732:16)
  flutter: #32     Element.rebuild (package:flutter/src/widgets/framework.dart:3547:5)
  flutter: #33     StatefulElement.update (package:flutter/src/widgets/framework.dart:3878:5)
  flutter: #34     Element.updateChild (package:flutter/src/widgets/framework.dart:2742:15)
  flutter: #35     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3732:16)
  flutter: #36     Element.rebuild (package:flutter/src/widgets/framework.dart:3547:5)
  flutter: #37     ProxyElement.update (package:flutter/src/widgets/framework.dart:3990:5)
  flutter: #38     Element.updateChild (package:flutter/src/widgets/framework.dart:2742:15)
  flutter: #39     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3732:16)
  flutter: #40     Element.rebuild (package:flutter/src/widgets/framework.dart:3547:5)
  flutter: #41     StatefulElement.update (package:flutter/src/widgets/framework.dart:3878:5)
  flutter: #42     Element.updateChild (package:flutter/src/widgets/framework.dart:2742:15)
  flutter: #43     SingleChildRenderObjectElement.update (package:flutter/src/widgets/framework.dart:4867:14)
  flutter: #44     Element.updateChild (package:flutter/src/widgets/framework.dart:2742:15)
  flutter: #45     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3732:16)
  flutter: #46     Element.rebuild (package:flutter/src/widgets/framework.dart:3547:5)
  flutter: #47     StatelessElement.update (package:flutter/src/widgets/framework.dart:3781:5)
  flutter: #48     Element.updateChild (package:flutter/src/widgets/framework.dart:2742:15)
  flutter: #49     SingleChildRenderObjectElement.update (package:flutter/src/widgets/framework.dart:4867:14)
  flutter: #50     Element.updateChild (package:flutter/src/widgets/framework.dart:2742:15)
  flutter: #51     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3732:16)
  flutter: #52     Element.rebuild (package:flutter/src/widgets/framework.dart:3547:5)
  flutter: #53     StatefulElement.update (package:flutter/src/widgets/framework.dart:3878:5)
  flutter: #54     Element.updateChild (package:flutter/src/widgets/framework.dart:2742:15)
  flutter: #55     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3732:16)
  flutter: #56     Element.rebuild (package:flutter/src/widgets/framework.dart:3547:5)
  flutter: #57     StatefulElement.update (package:flutter/src/widgets/framework.dart:3878:5)
  flutter: #58     Element.updateChild (package:flutter/src/widgets/framework.dart:2742:15)
  flutter: #59     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3732:16)
  flutter: #60     Element.rebuild (package:flutter/src/widgets/framework.dart:3547:5)
  flutter: #61     ProxyElement.update (package:flutter/src/widgets/framework.dart:3990:5)
  flutter: #62     Element.updateChild (package:flutter/src/widgets/framework.dart:2742:15)
  flutter: #63     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3732:16)
  flutter: #64     Element.rebuild (package:flutter/src/widgets/framework.dart:3547:5)
  flutter: #65     ProxyElement.update (package:flutter/src/widgets/framework.dart:3990:5)
  flutter: #66     Element.updateChild (package:flutter/src/widgets/framework.dart:2742:15)
  flutter: #67     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3732:16)
  flutter: #68     Element.rebuild (package:flutter/src/widgets/framework.dart:3547:5)
  flutter: #69     StatefulElement.update (package:flutter/src/widgets/framework.dart:3878:5)
  flutter: #70     Element.updateChild (package:flutter/src/widgets/framework.dart:2742:15)
  flutter: #71     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3732:16)
  flutter: #72     Element.rebuild (package:flutter/src/widgets/framework.dart:3547:5)
  flutter: #73     BuildOwner.buildScope (package:flutter/src/widgets/framework.dart:2286:33)
  flutter: #74     _WidgetsFlutterBinding&amp;BindingBase&amp;GestureBinding&amp;ServicesBinding&amp;SchedulerBinding&amp;PaintingBinding&amp;SemanticsBinding&amp;RendererBinding&amp;WidgetsBinding.drawFrame (package:flutter/src/widgets/binding.dart:676:20)
  flutter: #75     _WidgetsFlutterBinding&amp;BindingBase&amp;GestureBinding&amp;ServicesBinding&amp;SchedulerBinding&amp;PaintingBinding&amp;SemanticsBinding&amp;RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:219:5)
  flutter: #76     _WidgetsFlutterBinding&amp;BindingBase&amp;GestureBinding&amp;ServicesBinding&amp;SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:990:15)
  flutter: #77     _WidgetsFlutterBinding&amp;BindingBase&amp;GestureBinding&amp;ServicesBinding&amp;SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:930:9)
  flutter: #78     _WidgetsFlutterBinding&amp;BindingBase&amp;GestureBinding&amp;ServicesBinding&amp;SchedulerBinding._handleDrawFrame (package:flutter/src/scheduler/binding.dart:842:5)
  flutter: #79     _invoke (dart:ui/hooks.dart:154:13)
  flutter: #80     _drawFrame (dart:ui/hooks.dart:143:3)
  flutter: ════════════════════════════════════════════════════════════════════════════════════════════════════
  </code></pre>
  
  <p>Which I've made sure to check I'm not getting anything null but I still get it.</p>
  
  <p>And the second.
  When the timer finishes I get the following error:</p>
  
  <pre><code>[VERBOSE-2:shell.cc(184)] Dart Error: Unhandled exception:
  setState() called after dispose(): _TimeState#10749(lifecycle state: defunct, not mounted)
  This error happens if you call setState() on a State object for a widget that no longer appears in the widget tree (e.g., whose parent widget no longer includes the widget in its build). This error can occur when code calls setState() from a timer or an animation callback. The preferred solution is to cancel the timer or stop listening to the animation in the dispose() callback. Another solution is to check the "mounted" property of this object before calling setState() to ensure the object is still in the tree.
  This error might indicate a memory leak if setState() is being called because another object is retaining a reference to this State object after it has been removed from the tree. To avoid memory leaks, consider breaking the reference to this object during dispose().
  #0      State.setState.&lt;anonymous closure&gt; (package:flutter/src/widgets/framewo&lt;…&gt;
  </code></pre>
  
  <p>And when I try to start a timer again I get this:</p>
  
  <pre><code>flutter: Another exception was thrown: NoSuchMethodError: The getter 'inMilliseconds' was called on null.
  </code></pre>
  
  <p>Here's is my code:</p>
  
  <pre><code>import 'dart:async';
  import 'dart:math';
  
  import 'package:flutter/material.dart';
  import 'package:fluttery/layout.dart';
  
  Duration time;
  Duration previousTime;
  Duration currentTime;
  AnimationController timeController, circleController;
  bool reverse = false;
  
  void main() =&gt; runApp(MyApp());
  
  class MyApp extends StatelessWidget {
    @override
    Widget build(BuildContext context) {
      return MaterialApp(
        title: 'Flutter Demo',
        theme: ThemeData(
          primarySwatch: Colors.blue,
        ),
        home: MyHomePage(),
      );
    }
  }
  
  class MyHomePage extends StatefulWidget {
    @override
    _MyHomePageState createState() =&gt; _MyHomePageState();
  }
  
  class _MyHomePageState extends State&lt;MyHomePage&gt; with TickerProviderStateMixin {
  
    Stopwatch stopwatch = new Stopwatch();
  
    @override
    void initState() {
      super.initState();
      timeController = new AnimationController(
        duration: const Duration(milliseconds: 250),
        vsync: this,
      );
      timeController.addListener(() {
        setState(() {});
      });
    }
  
    @override
    void dispose() {
      timeController.dispose();
      circleController.dispose();
      super.dispose();
    }
  
    @override
    Widget build(BuildContext context) {
      return Scaffold(
        body: Stack(
          children: &lt;Widget&gt;[
            Center(
              child: Opacity(
                opacity: timeController.value != null ? 1.0 - timeController.value : 1.0,
                child: Column(
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: &lt;Widget&gt;[
                    new FlatButton(
                      onPressed: () {
                        setState(() {
                          previousTime = Duration(minutes: 1);
                          time = previousTime;
                          timeController.forward();
                          stopwatch.start();
                          circleController = new AnimationController(
                            duration: Duration(milliseconds: time.inMilliseconds),
                            vsync: this,
                          );
                          circleController.addListener(() {
                            setState(() {});
                          });
                          circleController.forward();
                        });
                      },
                      child: Text("1:00",
                          style: TextStyle(
                              fontWeight: FontWeight.bold, fontSize: 16.0)),
                    ),
                    new FlatButton(
                      onPressed: () {
                        setState(() {
                          previousTime = Duration(minutes: 2);
                          time = previousTime;
                          timeController.forward();
                          stopwatch.start();
                          circleController = new AnimationController(
                            duration: Duration(milliseconds: time.inMilliseconds),
                            vsync: this,
                          );
                          circleController.addListener(() {
                            setState(() {});
                          });
                          circleController.forward();
                        });
                      },
                      child: Text("2:00",
                          style: TextStyle(
                              fontWeight: FontWeight.bold, fontSize: 16.0)),
                    ),
                    new FlatButton(
                      onPressed: () {
                        setState(() {
                          previousTime = Duration(minutes: 3);
                          time = previousTime;
                          timeController.forward();
                          stopwatch.start();
                          circleController = new AnimationController(
                            duration: Duration(milliseconds: time.inMilliseconds),
                            vsync: this,
                          );
                          circleController.addListener(() {
                            setState(() {});
                          });
                          circleController.forward();
                        });
                      },
                      child: Text("3:00",
                          style: TextStyle(
                              fontWeight: FontWeight.bold, fontSize: 16.0)),
                    ),
                    new FlatButton(
                      onPressed: () {
                        setState(() {
                          previousTime = Duration(minutes: 5);
                          time = previousTime;
                          timeController.forward();
                          stopwatch.start();
                          circleController = new AnimationController(
                            duration: Duration(milliseconds: time.inMilliseconds),
                            vsync: this,
                          );
                          circleController.addListener(() {
                            setState(() {});
                          });
                          circleController.forward();
                        });
                      },
                      child: Text("5:00",
                          style: TextStyle(
                              fontWeight: FontWeight.bold, fontSize: 16.0)),
                    ),
                  ],
                ),
              ),
            ),
            Center(
              child: Opacity(
                opacity: timeController.value != null ? 0.0 + timeController.value : 0.0,
                child: Column(
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: time != null ? buildTimes(stopwatch, time, previousTime) : []
                ),
              ),
            ),
            CenterAbout(
                position: Offset(MediaQuery.of(context).size.width / 2,
                    MediaQuery.of(context).size.height / 2),
                child: Peinture(color: Color.fromRGBO(224, 245, 255, 1.0), animate: false)
            ),
            CenterAbout(
              position: Offset(MediaQuery.of(context).size.width / 2,
                  MediaQuery.of(context).size.height / 2),
              child: Peinture(color: Colors.blue, animate: true)
            )
          ],
        ),
      );
    }
  }
  
  List&lt;Widget&gt; buildTimes(stopwatch, time, previousTime) {
    return [
      Time(stopwatch: stopwatch, time: time),
      Text(
        previousTime != null
            ? previousTime.toString().substring(3, 7)
            : "",
        style: TextStyle(
            fontWeight: FontWeight.bold,
            fontSize: 30.0,
            color: Colors.black54),
      ),
    ];
  }
  
  class Peinture extends StatefulWidget {
  
    final Color color;
    final bool animate;
  
    Peinture({this.color, this.animate});
  
    @override
    _PeintureState createState() =&gt; _PeintureState(color: color, animate: animate);
  }
  
  class _PeintureState extends State&lt;Peinture&gt; {
    Timer timer;
    Color color;
    bool animate;
  
    _PeintureState({this.color, this.animate}) {
      timer = Timer.periodic(Duration(milliseconds: 1), callback);
    }
  
    void callback(Timer timer) {
      setState(() {
        if (currentTime != null) {
          print(currentTime.inMilliseconds);
          if (currentTime.inMilliseconds &lt;= 0) {
            reverse = true;
            timeController.reverse();
            previousTime = null;
            time = previousTime;
            currentTime = time;
            reverse = false;
          }
        }
      });
    }
  
    @override
    Widget build(BuildContext context) {
      return Opacity(
        opacity: reverse == false ? 1.0 : timeController.value,
        child: CustomPaint(
          painter: CirclePainter(
            radius: 150.0,
            thickness: 8.0,
            color: color,
            startAngle: -pi / 2,
            endAngle: time != null &amp;&amp; animate ? -pi / 2 + (((currentTime.inMilliseconds - circleController.value)) /  60000) * (2*pi) : -pi / 2 + (2 * pi) - (0 / (2*pi)),
          ),
        ),
      );
    }
  }
  
  
  class CirclePainter extends CustomPainter {
    final double radius;
    final double thickness;
    final Color color;
    final double startAngle;
    final double endAngle;
    final Paint circlePaint;
  
    CirclePainter({this.radius, this.thickness, this.color, this.startAngle, this.endAngle})
        : circlePaint = new Paint()
            ..color = color
            ..strokeWidth = thickness
            ..style = PaintingStyle.stroke
            ..strokeCap = StrokeCap.round;
  
    @override
    void paint(Canvas canvas, Size size) {
      canvas.drawArc(Rect.fromLTWH(-radius, -radius, radius * 2, radius * 2),
          startAngle, endAngle - startAngle, false, circlePaint);
    }
  
    @override
    bool shouldRepaint(CustomPainter oldDelegate) {
      return true;
    }
  }
  
  class Time extends StatefulWidget {
    final Duration time;
    final Stopwatch stopwatch;
  
    Time({this.stopwatch, this.time});
  
    @override
    _TimeState createState() =&gt; _TimeState(stopwatch: stopwatch, time: time);
  }
  
  class _TimeState extends State&lt;Time&gt; {
    Timer timer;
    Duration time;
    Stopwatch stopwatch;
  
    _TimeState({this.time, this.stopwatch}) {
      timer = new Timer.periodic(new Duration(milliseconds: 1), callback);
    }
  
    void callback(Timer timer) {
      if (stopwatch.isRunning) {
        setState(() {
          currentTime = time - stopwatch.elapsed;
        });
      }
    }
  
    @override
    Widget build(BuildContext context) {
      return Text(
        currentTime != null ? currentTime.toString().substring(3, 7) : "",
        style: TextStyle(
            fontWeight: FontWeight.bold, fontSize: 60.0, color: Colors.black87),
      );
    }
  }
  </code></pre>
  
  <p>Thanks for the help and again any suggestions as to how you'd go about it would be appreciated.</p>