You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter调用API报错String非Map<String,dynamic>子类型排查修复

报错根因

这个类型异常触发点在JSON解析环节,核心是类型不匹配:
你当前的解析逻辑默认jsonDecode(response.body)返回对象的所有顶级字段值都是Map<String, dynamic>类型,无差别遍历所有values传入Modelclass.fromJson(该方法参数要求是Map类型)。但实际接口返回的顶级JSON是混合结构,包含String类型的字段(比如接口声明、图表名称这类文本字段),当遍历到String类型值传入fromJson时,就会抛出type 'String' is not a subtype of type 'Map<String, dynamic>'的未处理异常。
结合你给出的实现,还有两个连带逻辑错误:

  • 你定义的Modelclass本身就是映射整个接口顶级返回结构的类,不需要遍历values构造模型列表
  • 页面层用state.modelclass[2]索引取值,说明你错误将解析结果当成了同质列表,就算遍历阶段没触发类型错误,得到的集合也是混合了嵌套对象、字符串的无序集合,索引2对应的是字符串值,访问.time属性依然会报错。
问题代码定位

你当前Repo层的解析逻辑大概率是下面这种错误写法:

// 错误实现
final response = await http.get(Uri.parse('接口地址'));
if (response.statusCode == 200) {
  final decoded = jsonDecode(response.body);
  // 问题1:未校验解码结果类型,默认所有value都是Map结构
  // 问题2:无差别遍历顶级values,把字符串等非Map值传入fromJson
  final List<Modelclass> modelList = decoded.values.map((e) => Modelclass.fromJson(e)).toList();
  return modelList;
}

从你定义的Modelclass、Time、Bpi、USD四个类判断,你调用的是比特币价格查询类接口,该接口顶级返回结构是对象而非数组,包含time(嵌套对象)、disclaimer(字符串)、chartName(字符串)、bpi(嵌套对象)四个顶级字段,遍历values会依次拿到Map、String、String、Map四种不同类型的值。

修正方案

按以下步骤调整代码即可解决问题:

  1. 修正Repo层解析逻辑,不要遍历顶级values,直接将整个解码后的Map传入顶层模型的fromJson方法
// 正确的Repo实现
Future<Modelclass> fetchBpiData() async {
  final response = await http.get(Uri.parse('你的接口请求地址'));
  if (response.statusCode == 200) {
    // 显式做类型强转,提前校验解码结果格式
    final Map<String, dynamic> decodedData = jsonDecode(response.body) as Map<String, dynamic>;
    // 直接传入整个解码结果构造顶层模型,无需遍历
    return Modelclass.fromJson(decodedData);
  } else {
    throw Exception('请求失败,状态码:${response.statusCode}');
  }
}
  1. 修正所有模型类的fromJson方法,严格按字段层级做类型转换,不要跨层级传值
// 顶层模型示例,其余Time、Bpi、USD类按相同逻辑编写
class Modelclass {
  final Time time;
  final String disclaimer;
  final String chartName;
  final Bpi bpi;

  Modelclass({
    required this.time,
    required this.disclaimer,
    required this.chartName,
    required this.bpi,
  });

  factory Modelclass.fromJson(Map<String, dynamic> json) {
    return Modelclass(
      // 嵌套对象单独调用对应类的fromJson,传入对应字段的Map值
      time: Time.fromJson(json['time'] as Map<String, dynamic>),
      disclaimer: json['disclaimer'] as String,
      chartName: json['chartName'] as String,
      bpi: Bpi.fromJson(json['bpi'] as Map<String, dynamic>),
    );
  }
}
  1. 修正页面层渲染逻辑,不要用索引取值,直接访问模型实例的属性
// 错误写法:Text(state.modelclass[2].time.toString())
// 正确写法
Text(state.modelclass.time.toString())
// 如果需要展示具体时间字段,比如更新时间,可直接访问子属性:Text(state.modelclass.time.updated)
通用JSON解析注意事项
  • 写解析逻辑前先打印解码后的数据结构和runtimeType,确认每个字段的实际类型,不要靠猜写代码
  • 所有类型转换都加显式as强转,让类型不匹配问题在解析阶段就暴露,不要等到渲染层才触发异常
  • 只有当接口顶级返回的是JSON数组(解码后runtimeType为List)时,才遍历列表项构造模型列表;如果顶级是对象,直接传入对应顶层模型fromJson即可,不要遍历对象values
  • 解析前增加类型判断逻辑,比如先判断解码结果是Map还是List,再走对应解析分支,避免接口结构变动直接触发崩溃。

内容的提问来源于stack exchange,提问作者Diljith

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 23:09:59