Flutter progress indicator with slow async method

1.1k views Asked by At

when i try to use CircularProgressIndicator with slow async method, indicator is not shown. When i replace slow custom method with Timer.pereodic() that works fine. I am new in Flutter and do not understand what i am doing wrong

class _MyHomePageState extends State<MyHomePage> {
  bool _inProgress = false;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
        child: Container(
          width: 200,
          height: 200,
          child: Column(
            children: [
              _inProgress ? CircularProgressIndicator() : Text("ready"),
              FloatingActionButton(onPressed: _slowMethod)
            ],
          ),
        ),
      ),
    );
  }

  int fibonacci(int n) {
    return n <= 2 ? 1 : fibonacci(n - 2) + fibonacci(n - 1);
  }

  _slowMethod() async {
    setState(() {
      _inProgress = true;
    });

    for (int i = 20; i <= 100; ++i) {
      print(fibonacci(i));
    }

    setState(() {
      _inProgress = false;
    });
  }
}
1

There are 1 answers

0
Obum On BEST ANSWER

An async function runs synchronously until the first await keyword.

In the first place, there is no await keyword in the _slowMethod, and that technically means you need to wrap the "what-should-be-asynchronous" operation in a Future and await for it.

So what should be your solution is something like the following for the _slowMethod():

  _slowMethod() async {
    setState(() {
      _inProgress = true;
    });

    await Future(() {
      for (int i = 20; i <= 100; ++i) {
        print(fibonacci(i));
      }
    });

    setState(() {
      _inProgress = false;
    });
  }

But then as Richard Heap (@Richard Heap) pointed in the comments, the above would have issues working. If you run the code, the CircularProgressIndicator will have problems displaying because the main Dart thread has been hijacked by the demanding fibonacci sequence and your UI won't render properly.

I'm supposing that you really might not have a Fibonacci of up to 100 in production code. That probably, you used it to show us the problem. But even if it is the case or you have complex asynchronous operations, you could use Isolates as Richard mentioned.

If the asynchronous operation is not very demanding on the main thread, (like simply doing Future.delayed), awaiting the future should work.

The following snippet will behave as you expect.

  _slowMethod() async {
    setState(() {
      _inProgress = true;
    });

    await Future.delayed(const Duration(seconds: 3));

    setState(() {
      _inProgress = false;
    });
  }