0

I'm still trying to understand how future works in dart, I wrote a method, that fetches data from an API like so:

Future<CountryData> getCountryData(String country) async {
    CountryData data;
    await apiService.getCountryData(country).then((country) {
        data = country;
    });
      return data;
  } 

But when calling the method it does not wait for execution to complete. This is how the method is being called:

Future<void> _updateData() async {
    try {
      final dataRepository =
          Provider.of<DataRepository>(context, listen: false);
          **final endpointcountrydata = await dataRepository.getCountryData("nigeria");**
           final africaData = await dataRepository.getAfricaData();
      setState(() {
        _endpointsData = endpointsData;
        _countryData = endpointcountrydata;
        _africaModel = africaData;
      });

    } on SocketException catch (_) {
      showAlertDialog(
        context: context,
        title: 'Connection Error',
        content: 'Could not retrieve data. Please try again later.',
        defaultActionText: 'OK',
      );
    } catch (_) {
      showAlertDialog(
        context: context,
        title: 'Unknown Error',
        content: 'Please contact support or try again later.',
        defaultActionText: 'OK',
      );
    }
  }

Both methods (endpointcountrydata and africaData) don't wait for exceution to complete.

The _updateData() method is called on the initState like so:

@override
  void initState() {
    super.initState();
    final dataRepository = Provider.of<DataRepository>(context, listen: false);


     **dataRepository.getAfricaData().then((value){
       print(value);
     });**

    _updateData();
  }

I even tried calling the method (getAfricaData()) from initState, still not waiting.

where am I getting it wrong?

From answers below, I have tried this:

Future<CountryData> getCountryData(String country) async {
    CountryData data = await apiService.getCountryData(country);
      return data;
  } 

Then I instatiated a bool like so:

bool _isFetchingData;

This is how the _updateData method looks like:

  Future<void> _updateData() async {
    try {
      final dataRepository =
          Provider.of<DataRepository>(context, listen: false);
          final endpointcountrydata = await dataRepository.getCountryData("nigeria");
      final endpointsData = await dataRepository.getAllEndpointsData();
      final africaData = await dataRepository.getAfricaData();

      setState(() {
        _isFetchingData = true;
        _endpointsData = endpointsData;
        _countryData = endpointcountrydata;
        _africaModel = africaData;
      });
      if(_countryData != null && _africaModel != null){
        setState(() {
          _isFetchingData = false;
        });
      }
    } on SocketException catch (_) {
      showAlertDialog(
        context: context,
        title: 'Connection Error',
        content: 'Could not retrieve data. Please try again later.',
        defaultActionText: 'OK',
      );
    } catch (_) {
      showAlertDialog(
        context: context,
        title: 'Unknown Error',
        content: 'Please contact support or try again later.',
        defaultActionText: 'OK',
      );
    }
  }

Then Initstate:

  @override
  void initState() {
    super.initState();
    final dataRepository = Provider.of<DataRepository>(context, listen: false);
    _endpointsData = dataRepository.getAllEndpointsCachedData();

    _updateData();
  }

Yet, still not waiting. Pulling my hair out already.

user8107351
  • 367
  • 4
  • 20
  • What exactly is not waiting for execution to complete? If you call an asynchronous function, *everything* in the call chain must wait. If you're calling this from `initState`, since `initState` does not return a `Future`, it will necessarily return before your `Future`s complete. – jamesdlin Apr 22 '20 at 04:29
  • so how do I solve this issue?, Cos I think the problem is because I have multiple futures, how do I wait all? – user8107351 Apr 22 '20 at 13:49
  • why are you returning a Future if your awaiting for the result?? – Yadu Apr 22 '20 at 14:45
  • I guess my question wasn't clear: how are you determining that you're not waiting for your `Future`s? That is, what code is being executed prematurely? If you're determining this from `initState` returning too soon, then you will need to move that asynchronous execution out of `initState` and use, say, `FutureBuilder`. – jamesdlin Apr 22 '20 at 18:14

1 Answers1

0
**You shouldn't return a Future if your returning the actual Object**
CountryData getCountryData(String country) async {
    CountryData data = await apiService.getCountryData(country);
      return data;
  } 

Return type is a Future<CountryData> change it to CountryData

code always reaches an end it must reach an end if it doesn't errors like StackOverflow is thrown, all the long running programs are some kind of loops, runs the same code in frames, in synchronous programming while waiting for the lengthier processes like network requests code will block the thread the process is running on , where in asynchronous programming like the dart futures, a result will be made available in a future frame which will be run in separate mini thread which will not block main thread.

coming to your requirement, Using a future completer

   Future<CountryData> getCountryData(String country){
        final completer = Completer<CountryData>();
        completer.complete(apiService.getCountryData(country));
        return complete.future;
      } 

when you call the method getCountryData you will get Future<CountryData> object, but as you need CountryData from this future you need to await till the Future is resolved to the by adding the keyWord await in-front of the Future you obtained

var future = getCountryData();
CountryData cd = await future;

you can even do that directly

CountryData cd = await getCountryData();
Yadu
  • 2,979
  • 2
  • 12
  • 27