m8dotpie
m8dotpie

Reputation: 3

Async periodic setState

I'm trying to implement a function which will periodically add widget to my list (for example once at 2 seconds) and call setState to update the list, which I'm drawing.

I tried to just call setState(), it is working just once at all, I think setState just don't call functions. I tried to use even While(true) in function, but after setState it just breaks. Also I tried recursion, and it is also stops after one call.

class _HomePageState extends State<HomePage>{

  List<Widget> currentMessages = [];

  Future<void> addText() async {
      await Future.delayed(Duration(seconds: 2));
      setState((){
        currentMessages.add(Text("It works?"));
      });
  }

  @override
  Widget build(BuildContext context) {

    addText();

    return Scaffold(
      body: Center(
        child: ListView(
          children: (currentMessages.isEmpty ? <Widget>[Container()]:currentMessages),
        ),
      )
    );
  }
}

Upvotes: 0

Views: 286

Answers (2)

Doc
Doc

Reputation: 11671

This should work.

class _SOState extends State<SO> {
  List<Widget> currentMessages = [];

  Timer timer;

  @override
  void initState() {
    super.initState();

    const twoSec = const Duration(seconds: 2);
    timer = new Timer.periodic(twoSec, (Timer t) {
      setState(() {
        currentMessages.add(Text("It works?"));
      });
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: ListView.builder(
          itemCount: currentMessages.length,
          itemBuilder: (BuildContext context, int index) {
            if (currentMessages.length == 0) return Container();
            return currentMessages[index];
          },
        ),
      ),
    );
  }

  @override
  void dispose() {
    timer.cancel();
    super.dispose();
  }
}

Don't know why ListView doesn't update on changes for your code. So I used a builder.

Upvotes: 0

Richard Heap
Richard Heap

Reputation: 51750

Override initState and dispose and create and cancel the timer in each respectively. For example:

class MyAppState extends State<MyApp> {
  Timer t;

  @override
  void initState() {
    super.initState();
    t = Timer.periodic(
      Duration(seconds: 1),
      (_) {
        setState(() {
          // do something here that will happen every second
        });
      },
    );
  }

  @override
  void dispose() {
    t?.cancel();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Container();
  }
}

Upvotes: 1

Related Questions