Home > Mobile >  Flutter: Update the UI with value from an async function
Flutter: Update the UI with value from an async function

Time:06-20

I want to see a the value of a counter in a flutter UI when the counter is updated asynchronously.

Staring from the sample flutter project, I would expect the below would make it, but only the final value is displayed. How can I achieve to see the numbers changing from 1 to 100000?

import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  void _incrementCounter() async {
    for(int i=0; i<100000;   i) {
      setState(() {
        _counter  ;
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            const Text(
              'You have pushed the button this many times:',
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.headline4,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ), // This trailing comma makes auto-formatting nicer for build methods.
    );
  }
}

CodePudding user response:

I think the issue is just that your loop is running too fast to show the intermediate values. Slowing the loop down with Future.delayed() should let you see what you want.

void _incrementCounter() async {
  for(int i=0; i<100000;   i) {
    await Future.delayed(Duration(seconds: 1));
    setState(() {
      _counter  ;
    });
  }
}

CodePudding user response:

to see the numbers changing from 1 to 100000 You can use Timer.periodic.

Creating state level timer variable to have control on running state.

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;
  Timer? _timer;

  void _incrementCounter() async {
    const delay = Duration(milliseconds: 100); // controll update speed
    const numberLimit = 100000;
    _timer = Timer.periodic(delay, (timer) {
      if (_counter < numberLimit) {
        setState(() {
          _counter  ;
        });
      } else {
        timer.cancel();
      }
    });
  }

  void _reset() {
    setState(() {
      _counter = 0;
    });
    _timer?.cancel();
  }

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

You can find more about dart-async-library and Timer.periodic on flutter.dev.

CodePudding user response:

import 'dart:async';

import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {

  late Timer _timer;
  int _start = 0;

  void startTimer() {
    const oneSec = const Duration(seconds: 1);
    _timer = new Timer.periodic(
        oneSec,
        (Timer timer) => setState(() {
              if (_start > 100000) {
                timer.cancel();
              } else {
                _start = _start   1;
              }
            }));
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            const Text(
              'You have pushed the button this many times:',
            ),
            Text(
              '$_start',
              style: Theme.of(context).textTheme.headline4,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: startTimer,
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ), // This trailing comma makes auto-formatting nicer for build methods.
    );
  }
}
  • Related