Flutter调用REST API解析响应时报List<dynamic>不是Map<String,dynamic>子类型错误
错误根因
实体类结构与接口实际返回结构不匹配,核心问题有2个:
- 接口返回的
data字段是List数组类型,但你在MealJSON类中将data声明为单个MealboxListing对象(本质是Map<String, dynamic>),赋值时触发了List转Map的类型错误 - 接口返回的
add_ons是UUID为key、附加项对象为value的键值对结构,但你在MealboxListing类中将addOns声明为单个AddOn对象,后续启用该字段解析也会触发类型错误
修复步骤
修改MealJSON类结构
将data字段类型改为List<MealboxListing>,同步调整解析逻辑:
class MealJSON { int code; List<MealboxListing> data; // 改这里,从单个对象改为列表 MealJSON({this.code, this.data}); MealJSON.fromJson(Map<String, dynamic> json) { code = json['code']; // 改这里,遍历数组解析为MealboxListing列表 data = (json['data'] as List<dynamic>?) ?.map((e) => MealboxListing.fromJson(e as Map<String, dynamic>)) .toList(); } Map<String, dynamic> toJson() { final Map<String, dynamic> data = new Map<String, dynamic>(); data['code'] = this.code; if (this.data != null) { data['data'] = this.data.map((e) => e.toJson()).toList(); } return data; } }
修改MealboxListing类
调整addOns字段类型,补全解析逻辑,同时优化数值转换避免报错:
class MealboxListing { // 改这里,从单个AddOn改为键值对Map Map<String, AddOn> addOns; bool availability; double averageRating; String cityLive; String deliveryDate; String description; List<String> imageDetails; String kitchenDetails; String listingId; int numberOfMeals; String origin; String title; List<String> preferences; List<String> tag; List<String> included; MealboxListing( {this.addOns, this.availability, this.averageRating, this.cityLive, this.deliveryDate, this.description, this.imageDetails, this.kitchenDetails, this.listingId, this.numberOfMeals, this.origin, this.title, this.preferences, this.tag, this.included}); MealboxListing.fromJson(Map<String, dynamic> json) { // 补全add_ons解析逻辑 addOns = (json['add_ons'] as Map<String, dynamic>?)?.map( (key, value) => MapEntry( key, AddOn.fromJson(value as Map<String, dynamic>), ), ); availability = json['available']; averageRating = json['average_rating']; cityLive = json['city_live']; deliveryDate = json['delivery_on']; description = json['description']; imageDetails = json['img_url'].cast<String>(); kitchenDetails = json['kitchen']; listingId = json['listing_id']; // 优化数值转换,兼容int和字符串两种返回格式 numberOfMeals = json['no_of_meals'] is int ? json['no_of_meals'] : int.parse(json['no_of_meals'].toString()); origin = json['origin']; title = json['title']; preferences = json['preferences'].cast<String>(); tag = json['tags'].cast<String>(); included = json['whats_included'].cast<String>(); } Map<String, dynamic> toJson() { final Map<String, dynamic> data = new Map<String, dynamic>(); if (this.addOns != null) { data['add_ons'] = this.addOns.map((key, value) => MapEntry(key, value.toJson())); } data['available'] = this.availability; data['average_rating'] = this.averageRating; data['city_live'] = this.cityLive; data['delivery_on'] = this.deliveryDate; data['description'] = this.description; data['img_url'] = this.imageDetails; data['kitchen'] = this.kitchenDetails; data['listing_id'] = this.listingId; data['no_of_meals'] = this.numberOfMeals; data['origin'] = this.origin; data['title'] = this.title; data['preferences'] = this.preferences; data['tags'] = this.tag; data['whats_included'] = this.included; return data; } }
修改API调用逻辑
适配返回的列表结构:
// 改返回值类型为列表 static Future<List<MealboxListing>?> getData() async { String vendorId = await secureStorage.read(key: "cust_id"); String token = await secureStorage.read(key: "access_token"); try { var res = await http.get( Uri.parse("你的接口地址"), headers: { "Content-Type": "application/json", 'Authorization': 'Bearer $token' }, ); if (res.statusCode == 200) { MealJSON mealJSON = mealFromJson(res.body); // mealJSON.data就是解析完成的餐盒列表 print(mealJSON.data?.first.description); return mealJSON.data; } } catch (e) { print(e.toString()); return null; } }
内容的提问来源于stack exchange,提问作者Ane Dev
相关产品推荐
相关产品推荐

