I have widget with data that changes regularly and I'm using a Timer.periodic to rebuild the widget. This starts out working smoothly but becomes choppy pretty quickly is there a better way to do this?

class _MainScreenState extends State<MainScreen> {

  static const Duration duration = Duration(milliseconds: 16);

  update(){
    system.updatePos(duration.inMilliseconds/1000);
    setState(() {});
  }


  @override
  Widget build(BuildContext context) {

    Timer.periodic(duration, (timer){
      update();
    });


    return PositionField(
      layoutSize: widget.square,
      children: system.map
    );
  }
}

1 Answers

0
boformer On Best Solutions

You are making a big mistake:

The build method must never have any side effects, because it is called again whenever setState is called (or when some higher up widget changes, or when the user rotates the screen...).

Instead, you want to create your Timer in initState, and cancel it on dispose:

class TimerTest extends StatefulWidget {
  @override
  _TimerTestState createState() => _TimerTestState();
}

class _TimerTestState extends State<TimerTest> {
  Timer _timer;

  int _foo = 0;

  // this is only called once when the widget is attached
  @override
  void initState() {
    super.initState();

    _timer = Timer.periodic(Duration(seconds: 1), (timer) => _update());
  }

  // stop the timer when the widget is detached and destroyed
  @override
  void dispose() {
    _timer.cancel();

    super.dispose();
  }

  void _update() {
    setState(() {
      _foo++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Text('Foo: ${_foo}');
  }
}