1

I have a tabbed screen with two tabs. One of the tabs is loaded with a google maps view. On that map I need to place custom markers, which (place id and geo coordinates) I fetch from an API. The relevant API call function is inside a mixin which I returns this object from the function.

My approach is as follows.

  • On tab view coming to screen, before the map view is shown to the user, I call this API function from the mixin.
  • I await for the result in a future builder inside the tab screen(the one holds the google maps view tab and the other one).
  • Soon after the function returns a response, I need to remove circular progress and show the two tab views.
  • For the google maps tab view I pass the markers list (an object list) as a parameter so in that screens initstate it will load the custom markers in places on the map.

So far my future builder is not performing correctly. I will showcase what I tried so far.

Future Builder

SafeArea(
      child: FutureBuilder(
        future: dataFuture,
        builder: (BuildContext ctx, AsyncSnapshot<dynamic> snapshot) {
          // Checking if future is resolved or not
          if (snapshot.connectionState == ConnectionState.done) {
            // If we got an error
            if (snapshot.hasError) {
              // setState(() {});
              return Center(
                child: Text(
                  '${snapshot.error} occured',
                  style: TextStyle(fontSize: 18),
                ),
              );

              // if we got our data
            } else if (snapshot.hasData) {
              _markersSet = snapshot.data as MarkerList;
              return Scaffold(
                appBar: SearchBar(
                  isFilterEnabled: false,
                ),
                body: _tabSection(),
                floatingActionButton:
                    page == true ? listViewFAB() : mapViewFAB(),
              );
            } else {
              return Center(
                child: Text(
                  '${snapshot.error} occured',
                  style: TextStyle(fontSize: 18),
                ),
              );
            }
          }
          return Center(
            child: CircularProgressIndicator(
              color: CustomColors.green600,
              strokeWidth: 6.0,
            ),
          );
        },
      ),
    );

//the tab views 
Widget _tabSection() {
    return DefaultTabController(
      // initialIndex: _selectedIndex,
      length: 2,
      child: TabBarView(
        controller: _tabCtrl,
        physics: NeverScrollableScrollPhysics(),
        children: [
          MainMapScreen(markersSet: _markersSet),
          MapListScreen(markersSet: _markersSet),
        ],
      ),
    );
  }

//_markersSet is the list or markers to be drawn on top of google maps.
//and same list is passed to a list view of markers in the other tab view.


//I call the dataFuture in initState before super.initState()
dataFuture = await getVenueDetails();

Mixin class

mixin FetchMarkers {
  final List<MarkerModel> eventList = [];
  final List<MarkerModel> accessibleList = [];
  late List<VenuesModel> vList = [];

//this is the list of markers I need to return above
  late MarkerList? markersSet = new MarkerList();

  Future<dynamic> getVenueDetails() async {
    GetConnection().getConnect().then((value) async {
      if (value) {
        final res = await APIHandler.instance.getVenuesDetails(
          endPoint: APIEndpoints.getVenues,
          // id: id!,
        );
        if (res != null) {
          if (res.code == 200) {
            vList = res.data;
            
            await loadEventList(vList);
            await loadAccessList(vList);
            //
            markersSet!.acList = accessibleList;
            markersSet!.evList = eventList;
            //
            log("get success venues ------------ ");
          } else {
            //status code not 200
            log("get failed != 200 ------------ ");
          }
        } else {
          //res is null
          log("get failed no response ------------ ");
        }
      } else {
        //   'No Network connectivity.\nPlease check the connection and try again',
        log("get failed no network ------------ ");
      }
      return markersSet!;
    });
  }

  Future<dynamic> loadEventList(List<VenuesModel> list) async {
    //loading event markers
    for (var i = 0; i < list.length; i++) {
      if (list[i].hasEvents == true) {
        var cats = list[i].categories;
        List<int> cList = [];
        for (var j in cats!) {
          cList.add(j.categoryId!);
        }
        var lat = list[i].lat;
        var lng = list[i].lng;
        eventList.add(MarkerModel(
          marker_id: i.toString(),
          marker_title: list[i].name,
          marker_pin: null,
          categories: cList,
          marker_place: list[i].venueId,
          marker_loc: LatLng(lat!, lng!),
        ));
      }
    }
    return eventList;
  }

  Future<dynamic> loadAccessList(List<VenuesModel> list) async {
    //loading venue markers
    for (var i = 0; i < list.length; i++) {
      if (list[i].hasEvents == false) {
        var cats = list[i].categories;
        List<int> cList = [];
        for (var j in cats!) {
          cList.add(j.categoryId!);
        }
        var lat = list[i].lat;
        var lng = list[i].lng;
        accessibleList.add(MarkerModel(
          marker_id: i.toString(),
          marker_title: list[i].name,
          marker_pin: null,
          categories: cList,
          marker_place: list[i].venueId,
          marker_loc: LatLng(lat!, lng!),
        ));
      }
    }
    return accessibleList;
  }
}

After multiple debugs I didn't get a result from the future builder, and when debugging the future builders ,

if (snapshot.connectionState == ConnectionState.done) {...}

is invoked before the API call function finishes. What am I doing wrong here? Can I get some guidance to rectify the above issue and make it performed well with flutter. P.S. Im using dio package for API handling.

Pixxu Waku
  • 423
  • 8
  • 21
  • if you have `async` method (`getVenueDetails`) why do you use `Future.then` at all? it is much more easy to use `await ...` only and avoid the problems you have now – pskink Feb 12 '22 at 06:05
  • so the line "GetConnection().getConnect().then((value) async { if (value) { .. " checks if the network is presented or not. if presented it will return value == true. you are suggesting to remove that line ? – Pixxu Waku Feb 12 '22 at 06:39
  • no, you should use `async` method with `await ...` only - you should remove `.then` method that only makes you troubles - like `final connected = await GetConnection().getConnect()` – pskink Feb 12 '22 at 06:42
  • Thank you for the insight. I made few changes in the code and matched relevant return values for Futures and async operations. trying few debugs – Pixxu Waku Feb 12 '22 at 07:06

0 Answers0