skip to Main Content

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


  1. Chosen as BEST ANSWER

    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.

      var getDirectionsInMiles;
      @override
      void initState(){
        super.initState();
        getDirectionsInMiles = getMeterDirections(widget.getLoc);
      }
    

    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.


  2. Here is what you can do,

    Instead of having userlocation as the future of FutureBuilder

    return FutureBuilder(
          future: userLocation,
    

    You can just use getLocDistance as the future.

    return FutureBuilder(
          future: getLocDistance(getLoc),
    

    and then update your getLocDistance as follows:

    Future<String> getLocDistance(getLoc) async {
      final latlng = await userLocation();
      PolylinePoints polylinePoints = PolylinePoints();
      PolylineResult result = await polylinePoints.getRouteBetweenCoordinates(
       googleMapsApi,
       PointLatLng(getLoc.latitude, getLoc.longitude),
       PointLatLng(latlng.latitude, latlng.longitude),
       travelMode: TravelMode.driving,
      );
    // rest of the code
    }
    

    and you will directly get distance in your builder.

    if (snapshot.hasData) {
          final distance = snapshot.data!;
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search