Flutter - Is it possible to extract data from a Future without using a FutureBuilder?

FutureBuilder is just a convenient helper to get the widget tree rebuilt when a Future completes.

You can use

funcThatReturnsFuture().then((result) {
  print(result);
  setState(() {
    someVal = result;
  })
})

or

Future funcThatMakesAsyncCall() async {
  var result = await funcThatReturnsFuture();
  print(result);  
  setState(() {
    someVal = result;
  })
}

The main limitation is that you can't return the value directly to the caller without a Future, because there is no way to get back from async execution to sync execution.


I've since figured this out (I believe this is what Günter was originally saying, but the fundamental reason why wasn't clear to me at the time). The only way to be able to consume a Future without creating a Widget object is by using the Future API. The Future API allows the parsing of a Future object as though it was an AsyncSnapshot object (which is where one would parse .data in a FutureBuilder builder: function). This can be performed on a returned Future object (which can use async with await). For example:

Future regionName = dbClient.getRegionNameFromZipCode(int.parse(zipCode)); <-- this database method getRegionNameFromZipCode returns a Future object and uses async and await

regionName.then((data) {
   String hZonesString = data[0]['hzone'];
   print(hZonesString);
}, onError: (e) {
     print(e);
   });

This is rather simple once you understand how the Future API can be leveraged, and it's intent vs. using FutureBuilder. Good to know for newbies of this language such as myself!


A Future is just semantic sugar for a callback. Imagine you had:

void fetchName(void Function(String) callback);

void main() {
  fetchName((name) {
     print('Your name is: $name');
  });
}

There isn't a way to convert (or extract) name from fetchName. It doesn't exist until the callback is completed, and the callback may not be completed immediately (could be read from a database, like your example, or the network, etc).

One of the advantages of using FutureBuilder is it really helps make sense of asynchronous abstractions like Future (and StreamBuilder for Stream), and let you focus on writing (synchronous) builder code:

new FutureBuilder<String>(
  future: _calculation, // a Future<String> or null
  builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
    switch (snapshot.connectionState) {
      case ConnectionState.none: return new Text('Press button to start');
      case ConnectionState.waiting: return new Text('Awaiting result...');
      default:
        if (snapshot.hasError)
          return new Text('Error: ${snapshot.error}');
        else
          return new Text('Result: ${snapshot.data}');
    }
  },
)

Tags:

Dart

Flutter