Flutter: Firing multiple Futures at the same time with FutureGroup

Updated: October 4, 2022 By: A Goodman Post a comment

This article shows you how to fire multiple futures at the same time and run them in parallel by using the FutureGroup class in Flutter. We’ll explore the fundamentals of the class and then walk through a complete example of using it in practice.

Overview

The add() and close() methods

In order to use the FutureGroup class, you need to import package:async/async.dart into your code:

import 'package:async/async.dart';

FutureGroup is a collection of futures that waits until all added features are complete. New futures are added to the group by using the add() method, like this:

FutureGroup _futureGroup = FutureGroup();

futureGroup.add(futureOne());
futureGroup.add(futureTwo());
...
futureGroup.add(futureN());

The close() method signals to the group that the caller is done adding futures, and a final future (see the future property listed below) will fire when all added futures have been completed.

Main Properties

  • future: The future that fires when the close() method has been called, and all futures in the group have been completed.
  • isClosed: Whether the group is closed.
  • isIdle: Whether the group has no futures.
  • onIdle: Emits an event whenever the group becomes idle.

Words might be tedious and confusing. For more clarity, please examine the example below.

The Complete Example

App Preview

The app we are going to make contains a floating button and displays a number or a loading indicator in the center of the screen. The number is obtained by summing the results returned from 3 different asynchronous functions: _futureOne, _futureTwo, and _futureThree. These functions have a delay of 1, 2, and 3 seconds, respectively.

As you will see in the following demo, the final result appears after about 3 seconds (equals the time it takes for _futureThree to complete). Because our futures run in parallel, the waiting time is 3 seconds, not 6 seconds.

Final Code

The complete source code with explanations in main.dart:

import 'package:flutter/material.dart';
import 'package:async/async.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      // Hide the debug banner
      debugShowCheckedModeBanner: false,
      title: 'KindaCode.com',
      theme: ThemeData(
        // use Material 3
        useMaterial3: true,
        primarySwatch: Colors.indigo,
      ),
      home: const HomeScreen(),
    );
  }
}

class HomeScreen extends StatefulWidget {
  const HomeScreen({Key? key}) : super(key: key);

  @override
  State<HomeScreen> createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
  // This number will be displayed on the screen
  int _result = 0;

  // This is used to conditionally display a loading indicator
  bool _isLoading = false;

  // Future 1
  Future<int> _futureOne() async {
    await Future.delayed(const Duration(seconds: 1));
    return 1;
  }

  // Future 2
  Future<int> _futureTwo() async {
    await Future.delayed(const Duration(seconds: 2));
    return 2;
  }

  // Future 3
  Future<int> _futureThree() async {
    await Future.delayed(const Duration(seconds: 3));
    return 3;
  }

  // This will be called when the floating action button is pressed
  void _fireFutureGroup() async {
    setState(() {
      _isLoading = true;
    });

    final FutureGroup<int> futureGroup = FutureGroup<int>();

    // Adding futures
    futureGroup.add(_futureOne());
    futureGroup.add(_futureTwo());
    futureGroup.add(_futureThree());

    // Signals that the adding process is done
    futureGroup.close();

    // Firing the future from the FutureGroup.future property
    final List<int> results = await futureGroup.future;
    debugPrint(results.toString());

    // Calculating the sum of the numbers from _results
    int sum = 0;
    for (int number in results) {
      sum += number;
    }

    // Re-render UI
    setState(() {
      _isLoading = false;
      _result = sum;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('KindaCode.com'),
      ),
      body: Center(
        child: _isLoading
            ? const CircularProgressIndicator()
            : Text(
                _result.toString(),
                style: const TextStyle(fontSize: 100, color: Colors.purple),
              ),
      ),
      // This button is used to trigger the future group
      floatingActionButton: FloatingActionButton(
        onPressed: _fireFutureGroup,
        child: const Icon(Icons.play_arrow),
      ),
    );
  }
}

Conclusion

You’ve learned how to run multiple futures simultaneously by using the FutureGroup class. If you’d like to explore more new and interesting things about Flutter, take a look at the following articles:

You can also take a tour around our Flutter topic page and Dart topic page to see the latest tutorials and examples.

Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments

Related Articles