Home > Software engineering >  snapshot.hasData returning false even though response.body has data [Flutter]
snapshot.hasData returning false even though response.body has data [Flutter]

Time:07-02

I am trying to get current weather info from OpenWeather and display the result in Text Widget after checking that there is data returned. However, that condtion (snapshot.hasData) is always returned as false and else condition (CircularProgressIndicator) is invoked. Here is the FutureBuilder.

class WeatherPage extends StatefulWidget {
  @override
  State<WeatherPage> createState() => _WeatherPageState();
}

class _WeatherPageState extends State<WeatherPage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: FutureBuilder(
          future: getCurrentWeather(),
          builder: (context, snapshot) {
            if (snapshot.hasData) {
              WeatherModelCurrent weather =
                  snapshot.data as WeatherModelCurrent;

              return weatherBox(weather);
            } else {
              return const CircularProgressIndicator();
            }
          },
        ),
      ),
    );
  }

here is the getCurrentWeather() function

Future getCurrentWeather() async {
    WeatherModelCurrent? weather;

    var url = Uri.parse(
        "https://api.openweathermap.org/data/2.5/weather?q=Kathmandu&appid=82c7b99e2a8215351147f607592a3e63&units=metric");
    var response = await http.get(url);
//response.body has the data returned by API call
    print(response.body);

    if (response.statusCode == 200) {
      weather = WeatherModelCurrent.frommJson(jsonDecode(response.body));
    
    } else {
      print('error');
    }

    return weather;
  }

and here is the model class

class WeatherModelCurrent {
  double temp;
  double feelslike;
  double tempmin;
  double tempmax;
  String description;

  WeatherModelCurrent(
      {required this.temp,
      required this.feelslike,
      required this.tempmin,
      required this.tempmax,
      required this.description});

  factory WeatherModelCurrent.frommJson(Map<String, dynamic> jsonn) {
    return WeatherModelCurrent(
      temp: jsonn['main']['temp'].toDouble(),
      feelslike: jsonn['main']['feels_like'].toDouble(),
      tempmin: jsonn['main']['temp_min'].toDouble(),
      tempmax: jsonn['main']['temp_max'].toDouble(),
      description: jsonn['weather']['description'],
    );
  }
}

CodePudding user response:

Try & catch your getCurrentWeather code block, we can get the following exception:

flutter: exception type 'String' is not a subtype of type 'int' of 'index'

The response json is like:

{
    "weather":[
        {
            "id":803,
            "main":"Clouds",
            "description":"broken clouds",
            "icon":"04d"
        }
    ],
}

Your code description: jsonn['weather']['description'] should be description: jsonn['weather'][0]['description'],

CodePudding user response:

The error is occur because you parse your response.body in wrong class. Try this model class

 class WeatherModelCurrent {
  WeatherModelCurrent({
this.coord,
this.weather,
this.base,
this.main,
this.visibility,
this.wind,
this.clouds,
this.dt,
this.sys,
this.timezone,
this.id,
this.name,
this.cod,
 });

 final Coord? coord;
 final List<Weather>? weather;
 final String? base;
final Main? main;
 final int? visibility;
 final Wind? wind;
 final Clouds? clouds;
 final int? dt;
 final Sys? sys;
 final int? timezone;
 final int? id;
 final String? name;
   final int? cod;

     factory WeatherModelCurrent.fromJson(Map<String, dynamic> json) =>  WeatherModelCurrent(
coord: Coord.fromJson(json["coord"]),
weather: List<Weather>.from(json["weather"].map((x) =>   Weather.fromJson(x))),
base: json["base"],
main: Main.fromJson(json["main"]),
visibility: json["visibility"],
wind: Wind.fromJson(json["wind"]),
clouds: Clouds.fromJson(json["clouds"]),
dt: json["dt"],
sys: Sys.fromJson(json["sys"]),
timezone: json["timezone"],
id: json["id"],
name: json["name"],
cod: json["cod"],
  );

  Map<String, dynamic> toJson() => {
  "coord": coord!.toJson(),
"weather": List<dynamic>.from(weather!.map((x) => x.toJson())),
"base": base,
"main": main!.toJson(),
"visibility": visibility,
"wind": wind!.toJson(),
"clouds": clouds!.toJson(),
"dt": dt,
"sys": sys!.toJson(),
"timezone": timezone,
"id": id,
"name": name,
"cod": cod,
};
}

class Clouds {
 Clouds({
this.all,
});

final int? all;

 factory Clouds.fromJson(Map<String, dynamic> json) => Clouds(
all: json["all"],
 );

 Map<String, dynamic> toJson() => {
 "all": all,
  };
 }

  class Coord {
 Coord({
this.lon,
this.lat,
});

final double? lon;
 final double? lat;

 factory Coord.fromJson(Map<String, dynamic> json) => Coord(
  lon: json["lon"].toDouble(),
  lat: json["lat"].toDouble(),
);

Map<String, dynamic> toJson() => {
"lon": lon,
"lat": lat,
 };
  }

  class Main {
Main({
this.temp,
this.feelsLike,
this.tempMin,
this.tempMax,
this.pressure,
this.humidity,
 });

 final double? temp;
final double? feelsLike;
final double? tempMin;
final double? tempMax;
final int? pressure;
final int? humidity;

factory Main.fromJson(Map<String, dynamic> json) => Main(
temp: json["temp"].toDouble(),
feelsLike: json["feels_like"].toDouble(),
tempMin: json["temp_min"].toDouble(),
tempMax: json["temp_max"].toDouble(),
pressure: json["pressure"],
humidity: json["humidity"],
);

Map<String, dynamic> toJson() => {
"temp": temp,
"feels_like": feelsLike,
"temp_min": tempMin,
"temp_max": tempMax,
"pressure": pressure,
"humidity": humidity,
  };
    }

 class Sys {
 Sys({
this.type,
this.id,
this.country,
this.sunrise,
this.sunset,
 });

 final int? type;
 final int? id;
final String? country;
final int? sunrise;
 final int? sunset;

 factory Sys.fromJson(Map<String, dynamic> json) => Sys(
type: json["type"],
id: json["id"],
country: json["country"],
sunrise: json["sunrise"],
sunset: json["sunset"],
 );

 Map<String, dynamic> toJson() => {
"type": type,
"id": id,
"country": country,
"sunrise": sunrise,
"sunset": sunset,
 };
  }

  class Weather {
  Weather({
this.id,
this.main,
this.description,
this.icon,
});

final int? id;
final String? main;
final String? description;
final String? icon;

 factory Weather.fromJson(Map<String, dynamic> json) => Weather(
  id: json["id"],
  main: json["main"],
  description: json["description"],
  icon: json["icon"],
);

Map<String, dynamic> toJson() => {
"id": id,
"main": main,
"description": description,
"icon": icon,
 };
}

  class Wind {
  Wind({
this.speed,
this.deg,
});

final double? speed;
final int? deg;

 factory Wind.fromJson(Map<String, dynamic> json) => Wind(
  speed: json["speed"].toDouble(),
  deg: json["deg"],
   );

Map<String, dynamic> toJson() => {
  "speed": speed,
  "deg": deg,
};
  }
  • Related