Flutter新手JSON解析报错:类型不匹配问题求助与代码修复
嘿,刚仔细看了你的代码和遇到的两个错误,这俩问题其实都是JSON结构和代码里的数据类型不匹配导致的,我来一步步帮你搞定~
先拆解错误原因
第一个错误:
'_InternalLinkedHashMap<String, dynamic>' is not a subtype of type 'List<dynamic>'
你的本地JSON文件应该是一个包含数组的对象(比如{"restaurants": [{}, {}, ...]}),但你直接把整个JSON响应当成List来解析了,jsonDecode(json)返回的是Map而非List,所以parseArticles里的类型转换就炸了。第二个错误:
type List dynamic is not a subtype of type 'List'
看你Resto类里把foods和drinks定义成了Map<String, String>,但实际JSON里的menus.foods和menus.drinks是数组(比如[{"name": "炸鸡"}, ...]),类型完全不匹配,自然报错。
一步步修复代码
1. 修复JSON解析逻辑(解决第一个错误)
修改parseArticles函数,先把JSON解析成Map,再取出里面的餐厅数组:
List<Resto> parseArticles(String json) { if (json == null) { return []; } // 先解析为Map,再提取restaurants数组 final Map<String, dynamic> parsedMap = jsonDecode(json); final List<dynamic> restoList = parsedMap['restaurants']; return restoList.map((json) => Resto.fromJson(json)).toList(); }
2. 修复Resto类的字段类型(解决第二个错误)
把foods和drinks改成List<String>,并修改fromJson方法来正确解析数组里的name字段:
import 'dart:convert'; class Resto { String id; String name; String description; String pictureId; String city; double rating; List<String> foods; // 改为List<String> List<String> drinks; // 改为List<String> Resto({ this.id, this.name, this.description, this.pictureId, this.city, this.rating, this.foods, this.drinks, }); Resto.fromJson(Map<String, dynamic> json) { id = json['id']; name = json['name']; description = json['description']; pictureId = json['pictureId']; city = json['city']; rating = json['rating']?.toDouble(); // 加空安全处理,防止rating为null // 解析foods数组,提取每个元素的name final List<dynamic> foodList = json['menus']['foods']; foods = foodList.map((food) => food['name'] as String).toList(); // 解析drinks数组,提取每个元素的name final List<dynamic> drinkList = json['menus']['drinks']; drinks = drinkList.map((drink) => drink['name'] as String).toList(); } }
3. 完善FutureBuilder的状态处理(避免崩溃)
你原来的代码直接用snapshot.data,没处理加载中、出错、空数据的情况,很容易崩溃,加上这些判断:
body: FutureBuilder<String>( future: DefaultAssetBundle.of(context).loadString('assets/local_restaurant.json'), builder: (context, snapshot) { // 加载中显示转圈 if (snapshot.connectionState == ConnectionState.waiting) { return const Center(child: CircularProgressIndicator()); } // 出错显示错误信息 if (snapshot.hasError) { return Center(child: Text('加载失败:${snapshot.error}')); } // 无数据提示 if (!snapshot.hasData || snapshot.data == null) { return const Center(child: Text('没有餐厅数据')); } // 解析并渲染列表 final List<Resto> restos = parseArticles(snapshot.data!); return ListView.builder( itemCount: restos.length, itemBuilder: (context, index) { return _buildArticleItem(context, restos[index]); }, ); }, ),
最后验证你的JSON结构
确保assets/local_restaurant.json的结构类似这样(如果你的键名不是restaurants,要对应修改parseArticles里的键):
{ "restaurants": [ { "id": "rqdv5juczeskfw1e867", "name": "Melting Pot", "description": "Lorem ipsum dolor sit amet...", "pictureId": "https://restaurant-api.dicoding.dev/images/large/14", "city": "Medan", "rating": 4.2, "menus": { "foods": [{"name": "Paket roti bakar"}, {"name": "Kebab"}], "drinks": [{"name": "Es Teh"}, {"name": "Es Jeruk"}] } } ] }
这样修改后,两个错误应该都能解决啦~
内容的提问来源于stack exchange,提问作者ivandriancode

