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}');
}
},
)