loading...
Cover image for Solve Async Callbacks with FutureBuilder!

Solve Async Callbacks with FutureBuilder!

sayanide profile image Sayan Mondal ・3 min read

Flutter and Dart are asynchronous in nature. Dart's Future provides a very smooth experience when it comes to handling I/O without worrying about threads or deadlocks.

A Future is used to represent a potential value, or error, that will be available at some time in the future.

Receivers of a Future can register callbacks that handle the value or error once it is available.

Future


Why FutureBuilder is required!

Suppose you want to return a widget in the build method but the data required in the widget comes from an async function.

class MyWidget extends StatelessWidget {
  @override
  Widget build(context) {
    yourAsyncFetch().then((data) {
      return ...yourStuff(with the data);
    });
  }
}

Provided that the fetch could be an HTTP call, a call to SQLite or any call in general that returns a Future, this approach won't really work out.

Because a Widget's build method is synchronous and it won't wait while you fetch data.


This is where FutureBuilder (FutureBuilder<T>) comes into the picture.


The Fix

A FutureBuilder takes a Future as an argument, as well as a builder (A delegate called by the widget's build method). The builder will be called immediately, and again when our future resolves with either data or an error.

A Future must not be created during build when constructing the FutureBuilder. If the future is created at the same time as the FutureBuilder, then every time the FutureBuilder's parent is rebuilt, the asynchronous task will be restarted.

An AsyncSnapshot<T> is simply a representation of that data/error state.

Future<String> yourAsyncFetch() => Future.delayed(Duration(seconds: 3), () => "Text coming after 3 seconds");

class MyWidget extends StatelessWidget {
  @override
  Widget build(context) {
    return FutureBuilder<String>(
      future: yourAsyncFetch(),
      builder: (context, AsyncSnapshot<String> snapshot) {
        if (snapshot.hasData) {
          return Text(snapshot.data); // Display the data from yourAsyncFetch() function after 3 seconds
        } else {
          return CircularProgressIndicator(); // Display a Circular Progress Indicator if the data is not fetched
        }
      }
    );
  }
}

Voila! Problem Solved.



Effect on Performance

FutureBuilder is just a StatefulWidget whose state is a _snapshot. It's initial state is _snapshot = AsyncSnapshot<T>.withData(ConnectionState.none, widget.initialData);

It subscribes to a future which we send and updates the state based on that.

widget.future.then<void>((T data) {
    if (_activeCallbackIdentity == callbackIdentity) {
       setState(() {
          _snapshot = AsyncSnapshot<T>.withData(ConnectionState.done, data);
       });
    }
}, onError: (Object error) {
    if (_activeCallbackIdentity == callbackIdentity) {
       setState(() {
          _snapshot = AsyncSnapshot<T>.withError(ConnectionState.done, error);
       });
    }
});

Thus the FutureBuilder is just a wrapper of what we normally do, so there is no impact on the performance.


Thank You

Conclusion

That's all folks 👨‍🏫, Thank you for reading it till the end. I hope this helped you get a better idea of FutureBuilder and its real application out there. If I missed out anything do let me know in the comments and we can have a brainstorm session! 👨🏻‍💻


Flutter

Flutter Kolkata is a group for people who wants to learn and explore Flutter Development. We invite both beginners as well as pro Dart accolades. Do join and get indulged with us on our Discord

Don't forget to share these resources with someone who you think might need some help with FutureBuilder too. Peace out. ✌🏼

Posted on by:

sayanide profile

Sayan Mondal

@sayanide

A coffee lover ☕ and explorer 🌏. In my free time I like to write Code and help the community out.

Discussion

pic
Editor guide