Search code examples
flutterdartdart-null-safety

_TypeError (type 'Null' is not a subtype of type 'FutureOr<Stations>')


Have recently installed Flutter null safety and having fixed most of the code I am having trouble with an API call.

It returns _TypeError (type 'Null' is not a subtype of type 'FutureOr<Stations>')

I haven't found a SO answer that seems to line up with my issue/ code method.

This is the button click that calls the API from main.dart

void _anchoredMapMarkersButtonClicked() {
    _mapMarkerExample.showAnchoredMapMarkers();
  }

And this is the API call itself with error displaying at the bottom } catch(Exception) { line

 Future<Stations> fetchStations() async {
    var client = http.Client();
    var stations;
     
   Position position = await Geolocator.getCurrentPosition(desiredAccuracy: LocationAccuracy.high);


    var lat = position.latitude;
    var long = position.longitude;
    
try{
    var response = await client.get(Uri.parse('https call'));
    if (response.statusCode == 200) {
   var jsonString = response.body;
   var jsonMap = json.decode(jsonString);
   
   stations = Stations.fromJson(jsonMap);
   //print(stations);
  }
} catch(Exception) {
  return stations;
}

  return stations;
}

Updated Code

Future<Stations> fetchStations() async {
    var client = http.Client();
    Stations? stations;
     
   Position position = await Geolocator.getCurrentPosition(desiredAccuracy: LocationAccuracy.high);
   print(position);


    var lat = position.latitude;
    var long = position.longitude;
    
try{
    var response = await client.get(Uri.parse('https://transit.hereapi.com/v8/stations?in=$lat,$long&return=transport&apiKey=uIioesb_EbnEXgPHlH0Z5e7gPGy9irpq2dRJcjuYPZY'));
    if (response.statusCode == 200) {
   var jsonString = response.body;
   var jsonMap = json.decode(jsonString);
   //print(jsonMap);
   inspect(jsonMap);
   
   stations = Stations.fromJson(jsonMap);
   //print(stations);
  }
} catch(Exception) {
  Future<Stations?> fetchStations()
}

  Future<Stations?> fetchStations()
}

Solution

  • when you enable null safety, each type is divided into nullable and non-nullable type, as shown in the following picture, from dart official docs Non-nullable and nullable types enter image description here

    So when you declare var stations, by default it have the value dynamic, which -in dart null safety- can be null, but the return of the function is of type Future<Stations>, in which the value of the future Stations can never be null (because it doesn't have the ? after the type),To solve this, you have to options:

    First option,

    declare your stations variable like this

    Stations? stations; // you tell the compiler that this variable can hold null value
    

    and then make the return of the function

    Future<Stations?> fetchStations() 
    

    this way it's valid that you return null from the function.

    Second option,

    is declaring stations as non null like this

    Stations stations; // this will give a compiler error
    

    but now you'll have a compiler error that stations is a non null type and you didn't it assign it any value, you can either assign an initial value to it

    Stations stations = Stations();
    

    Or, use the late keyword,

    late Stations stations; // tell the compiler that this is non null object that i'll assign a value to later
    

    but notice that in the latter, you have to assign stations a value at some point, if you don't you'll get an exception.

    if you chose the first option, the function should look like the following,

    Future<Stations?> fetchStations() async {
        var client = http.Client();
        Stations? stations;
         
       Position position = await Geolocator.getCurrentPosition(desiredAccuracy: LocationAccuracy.high);
    
    
        var lat = position.latitude;
        var long = position.longitude;
        
    try{
        var response = await client.get(Uri.parse('https call'));
        if (response.statusCode == 200) {
       var jsonString = response.body;
       var jsonMap = json.decode(jsonString);
       
       stations = Stations.fromJson(jsonMap);
       //print(stations);
      }
    } catch(e) {
      // you don't need to return stations, because you return it at the end of the function
      // return stations;
      print("Exception Happened: ${e.toString()}")
    }
      // you can return a nullable object because the function return type is a nullable type
      return stations; 
    }