I have this Stateless Widge and I am trying to dynamically get the driving distance from the users location to a predefined location and want to display the distance as a string. I have a Future request within a FutureBuilder. When I assign it to final this way I get Instance of Future. I have scoured the internet and yet to have found any thing with nested Future within a FutureBuilder. Is there a way to do this? Do I need to generate another async/await method to call and assign this future string?
I commented in the FutureBuilder where I want to assign the string value and the Future method call is below the FutureBuilder
Thanks in advance
class LocationInput extends StatelessWidget {
final getLoc;
LocationInput({Key? key, required this.getLoc}) : super(key: key);
PolylinePoints polylinePoints = PolylinePoints();
double _distInMeters = 0.0;
@override
Widget build(BuildContext context) {
var userLocation = determinePosition();
return FutureBuilder(
future: userLocation,
builder: ((BuildContext context, AsyncSnapshot<Position> snapshot) {
if (snapshot.hasData) {
final distance = getDistance(getLoc, snapshot); // THIS IS WHERE I WANT TO ASSIGN THE FUTURE<STRING> AS A STRING
return Padding(
padding: const EdgeInsets.only(right: 8.0, top: 12.0),
child: GestureDetector(
onTap: () {
getDirections(getLoc.latitude, getLoc.longitude);
},
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[Icon(Icons.directions)],
),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
Text("$distance mi"),
],
)
],
),
),
);
} else if (snapshot.hasError) {
return Center(
child: Text("An error has occurred please try again."),
);
} else {
return Center(
child: Padding(
padding: const EdgeInsets.only(right: 8.0),
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
IconButton(
onPressed: () {}, icon: const Icon(Icons.directions))
],
),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: const <Widget>[
Text(""),
],
)
],
),
),
);
}
}),
);
}
}
Future<String> getLocDistance(getLoc, snapshot) async {
List<LatLng> polylineCoordinates = [];
PolylinePoints polylinePoints = PolylinePoints();
PolylineResult result = await polylinePoints.getRouteBetweenCoordinates(
googleMapsApi,
PointLatLng(getLoc.latitude, getLoc.longitude),
PointLatLng(snapshot.data!.latitude, snapshot.data!.longitude),
travelMode: TravelMode.driving,
);
if (result.points.isNotEmpty) {
result.points.forEach((PointLatLng point) {
polylineCoordinates.add(LatLng(point.latitude, point.longitude));
});
} else {
print(result.errorMessage);
}
//polulineCoordinates is the List of longitute and latidtude.
double totalDistance = 0;
for (var i = 0; i < polylineCoordinates.length - 1; i++) {
totalDistance += calculateDistance(
polylineCoordinates[i].latitude,
polylineCoordinates[i].longitude,
polylineCoordinates[i + 1].latitude,
polylineCoordinates[i + 1].longitude);
}
return ((totalDistance * 1000) / 1609.344).toStringAsFixed(2);
}
2
Answers
I was able to solve this with the comments provided to me. I found resources eventually that putting together made more sense about futures. Here is what I ended up doing.
I converted the widget to stateful and created a reference to the future function in the state.
Then getting the userLocation in the getMeterDirections kept it so there was only 1 future being called in the future builder. It is not good practice to pass variables through the futurebuilder future.
Here is what you can do,
Instead of having
userlocation
as the future of FutureBuilderYou can just use
getLocDistance
as the future.and then update your
getLocDistance
as follows:and you will directly get
distance
in your builder.