Flutter解析JSON报错:String不是Map<String,dynamic>子类型
Flutter请求Flask接口类型转换异常排查
异常场景
Flutter开发过程中,请求本地Flask服务接口 http://192.168.1.24:5000/analyze 获取加密货币数据时,抛出未处理异常:
Unhandled Exception: type 'String' is not a subtype of type 'Map<String, dynamic>'
已知信息
- 接口返回结构:Flask接口返回JSON数组,数组内为加密货币数据条目,包含
atl_change_percentage、image、market_cap_rank等加密货币行情字段 - 现有实现:
- 已定义
CryptoInfo实体类,实现了接收Map<String, dynamic>入参的fromJson工厂构造方法 - 网络请求逻辑使用
http.get发起,通过jsonDecode解析响应体 - 页面层使用
FutureBuilder组件实现加载态、错误态、数据态的三态渲染
- 已定义
- 异常表现:
控制台打印接口响应状态码为200,可正常输出data[0]的完整内容,但执行CryptoInfo.fromJson(data[0])时触发类型不匹配错误,数据无法完成实体转换,页面不能正常渲染数据。
根因分析
接口返回的数组元素实际是JSON格式的字符串,而非结构化的键值对对象。jsonDecode仅处理了最外层的响应体,数组内的字符串元素没有被自动反序列化为Map<String, dynamic>类型,传入要求Map类型入参的fromJson方法时,就会触发类型不匹配错误。
修复方案
转换实体前,先判断数组元素的类型,如果是字符串类型,先做二次jsonDecode拿到Map结构,再传入实体类构造方法,核心实现代码如下:
import 'dart:convert'; import 'package:http/http.dart' as http; Future<List<CryptoInfo>> fetchCryptoData() async { final response = await http.get(Uri.parse('http://192.168.1.24:5000/analyze')); if (response.statusCode == 200) { // 解析外层响应体 final List<dynamic> rawData = jsonDecode(response.body); return rawData.map((item) { // 二次解析数组内的JSON字符串 final Map<String, dynamic> itemMap = item is String ? jsonDecode(item) : item as Map<String, dynamic>; return CryptoInfo.fromJson(itemMap); }).toList(); } else { throw Exception('接口请求失败,状态码:${response.statusCode}'); } }
校验方式
如果调整后仍存在问题,可在转换前打印data[0].runtimeType确认实际类型:
- 打印结果为
String时,上述二次解析方案可直接解决问题 - 打印结果为其他类型时,可排查Flask端的序列化逻辑,确认接口返回时没有将数据对象手动转成字符串后再放入数组。
内容的提问来源于stack exchange,提问作者Bill.xby
相关产品推荐
相关产品推荐

