Flutter类型转换错误:'Data'非'WeatherModel'子类型及城市名显示问题
解决Flutter调用Weatherbit API的类型转换错误及城市名称显示问题
错误根源
你遇到的type 'Data' is not a subtype of type 'WeatherModel' in type cast错误,本质是模型结构与API返回数据不匹配:Weatherbit的每日预报API返回的是一个顶层对象,包含city信息和data数组(存储每日天气数据),而你错误地将数组中的Data类型对象强转为顶层的WeatherModel类型。
步骤1:修正模型结构
确保你的模型正确对应API返回结构,顶层WeatherModel包含城市信息和每日天气列表:
class WeatherModel { final City city; final List<Data> data; WeatherModel({required this.city, required this.data}); factory WeatherModel.fromJson(Map<String, dynamic> json) { final dataList = json['data'] as List; final dailyWeatherList = dataList.map((item) => Data.fromJson(item)).toList(); return WeatherModel( city: City.fromJson(json['city']), data: dailyWeatherList, ); } } class City { final String cityName; City({required this.cityName}); factory City.fromJson(Map<String, dynamic> json) => City( cityName: json['city_name'], ); } class Data { // 根据需求添加每日天气字段,示例为日期和温度 final String datetime; final double temp; Data({required this.datetime, required this.temp}); factory Data.fromJson(Map<String, dynamic> json) => Data( datetime: json['datetime'], temp: json['temp'].toDouble(), ); }
步骤2:修改API服务解析逻辑
确保服务正确解析顶层WeatherModel,而不是直接处理数组元素:
import 'package:http/http.dart' as http; import 'dart:convert'; class WeatherService { final String apiKey = '5cea02af6cd6498d9524cedb8ab23b4c'; final String baseUrl = 'https://api.weatherbit.io/v2.0/forecast/daily'; Future<WeatherModel> fetchWeather(String city) async { final response = await http.get(Uri.parse('$baseUrl?city=$city&key=$apiKey')); if (response.statusCode == 200) { return WeatherModel.fromJson(json.decode(response.body)); } else { throw Exception('Failed to load weather data'); } } }
步骤3:调整页面代码,显示城市名称和天气列表
通过FutureBuilder获取WeatherModel实例,提取城市名称显示,同时用ListView.builder遍历data数组:
import 'package:flutter/material.dart'; class WeatherPage extends StatefulWidget { const WeatherPage({super.key}); @override State<WeatherPage> createState() => _WeatherPageState(); } class _WeatherPageState extends State<WeatherPage> { late Future<WeatherModel> futureWeather; @override void initState() { super.initState(); futureWeather = WeatherService().fetchWeather('Raleigh,NC'); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('Daily Weather Forecast')), body: FutureBuilder<WeatherModel>( future: futureWeather, builder: (context, snapshot) { if (snapshot.hasData) { return Column( children: [ // 显示城市名称 Padding( padding: const EdgeInsets.symmetric(vertical: 16), child: Text( snapshot.data!.city.cityName, style: const TextStyle( fontSize: 28, fontWeight: FontWeight.w600, ), ), ), // 每日天气列表 Expanded( child: ListView.builder( itemCount: snapshot.data!.data.length, itemBuilder: (context, index) { final dailyData = snapshot.data!.data[index]; return ListTile( title: Text(dailyData.datetime), subtitle: Text('Temperature: ${dailyData.temp}°C'), ); }, ), ), ], ); } else if (snapshot.hasError) { return Center(child: Text('Error: ${snapshot.error}')); } return const Center(child: CircularProgressIndicator()); }, ), ); } }
关键说明
- 之前的错误是因为你直接将API返回的
data数组中的元素(Data类型)强制转换为WeatherModel,现在通过先解析顶层WeatherModel,再从中提取每日数据列表,彻底解决类型不匹配问题。 - 城市名称通过
WeatherModel中的city字段直接获取并显示,无需额外处理。
内容的提问来源于stack exchange,提问作者Andaç Taşdemir
相关产品推荐
相关产品推荐

