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

Flutter调用API遇类型错误:List<dynamic>无法转为CustomerElement

解决Flutter API解析时的类型不匹配错误

问题场景

我正在用Flutter测试API工作流,用Obx包裹Card组件来基于API数据构建卡片。在这段代码处报错:

return CardList(customer: customerController.customerList[index];

抛出异常:

_TypeError (type 'List' is not a subtype of type 'CustomerElement')

调试时能看到customerList里已经有JSON数据,怀疑是模型定义的问题,但不确定。

API响应格式

后端返回的JSON结构如下:

[
    [
        {
            "customer_id": 1,
            "customer_title": "m",
            "customer_fname": "john",
            "customer_lname": "doe",
            "customer_email": "johndoe@mail.com",
            "customer_password": "john"
        },
        {
            "customer_id": 2,
            "customer_title": "f",
            "customer_fname": "jane",
            "customer_lname": "doe",
            "customer_email": "jane@female.com",
            "customer_password": "jane1234"
        }
    ],
    {
        "fieldCount": 0,
        "affectedRows": 0,
        "insertId": 0,
        "serverStatus": 34,
        "warningCount": 0,
        "message": "",
        "protocol41": true,
        "changedRows": 0
    }
]  

当前使用的模型代码(通过quicktype生成)

// To parse this JSON data, do
//
//     final customer = customerFromJson(jsonString);

import 'dart:convert';

List<dynamic> customerFromJson(String str) => List<dynamic>.from(json.decode(str).map((x) => x));

String customerToJson(List<dynamic> data) => json.encode(List<dynamic>.from(data.map((x) => x)));

class CustomerElement {
    CustomerElement({
       required this.customerId,
       required this.customerTitle,
       required this.customerFname,
       required this.customerLname,
       required this.customerEmail,
       required this.customerPassword,
    });

    int customerId;
    String customerTitle;
    String customerFname;
    String customerLname;
    String customerEmail;
    String customerPassword;

    factory CustomerElement.fromJson(Map<String, dynamic> json) => CustomerElement(
        customerId: json["customer_id"],
        customerTitle: json["customer_title"],
        customerFname: json["customer_fname"],
        customerLname: json["customer_lname"],
        customerEmail: json["customer_email"],
        customerPassword: json["customer_password"],
    );

    Map<String, dynamic> toJson() => {
        "customer_id": customerId,
        "customer_title": customerTitle,
        "customer_fname": customerFname,
        "customer_lname": customerLname,
        "customer_email": customerEmail,
        "customer_password": customerPassword,
    };
}

class PurpleCustomer {
    PurpleCustomer({
      required this.fieldCount,
      required this.affectedRows,
      required this.insertId,
      required this.serverStatus,
      required this.warningCount,
      required this.message,
      required this.protocol41,
      required this.changedRows,
    });

    int fieldCount;
    int affectedRows;
    int insertId;
    int serverStatus;
    int warningCount;
    String message;
    bool protocol41;
    int changedRows;

    factory PurpleCustomer.fromJson(Map<String, dynamic> json) => PurpleCustomer(
        fieldCount: json["fieldCount"],
        affectedRows: json["affectedRows"],
        insertId: json["insertId"],
        serverStatus: json["serverStatus"],
        warningCount: json["warningCount"],
        message: json["message"],
        protocol41: json["protocol41"],
        changedRows: json["changedRows"],
    );

    Map<String, dynamic> toJson() => {
        "fieldCount": fieldCount,
        "affectedRows": affectedRows,
        "insertId": insertId,
        "serverStatus": serverStatus,
        "warningCount": warningCount,
        "message": message,
        "protocol41": protocol41,
        "changedRows": changedRows,
    };
}

HTTP请求代码

class RemoteService {
  static var client = http.Client();

  static Future<List<dynamic>?> fetchCustomer() async {
    var url = Uri.parse('http://10.0.2.2:8000/test/getcustomer');

    var response = await client.get(url);

    if (response.statusCode == 200) {
      var jsonString = response.body;
      return customerFromJson(jsonString);
    } else {
      return null;
    }
  }
}

问题原因及解决方案

问题根源

API返回的是双层数组+对象的复合结构:

  1. 第一个元素是包含客户数据的数组[{}, {}]
  2. 第二个元素是数据库操作的元数据对象

当前解析逻辑直接把整个响应转成List<dynamic>,导致customerList[index]取到的是第一层的客户数组,而非单个CustomerElement对象,因此触发类型不匹配错误。

修复步骤

  1. 修改模型的解析函数,精准提取客户数据数组:
// 替换原来的customerFromJson函数
List<CustomerElement> customerFromJson(String str) {
  final decoded = json.decode(str);
  // 取响应中的第一个元素(客户数组),转换为CustomerElement列表
  return List<CustomerElement>.from(
    (decoded[0] as List).map((x) => CustomerElement.fromJson(x))
  );
}

// 同步调整toJson函数(按需使用)
String customerToJson(List<CustomerElement> data) => json.encode(
  List<dynamic>.from(data.map((x) => x.toJson()))
);
  1. 更新RemoteService的返回类型,明确返回List<CustomerElement>?:
class RemoteService {
  static var client = http.Client();

  static Future<List<CustomerElement>?> fetchCustomer() async {
    var url = Uri.parse('http://10.0.2.2:8000/test/getcustomer');

    var response = await client.get(url);

    if (response.statusCode == 200) {
      var jsonString = response.body;
      return customerFromJson(jsonString);
    } else {
      return null;
    }
  }
}
  1. 确保Controller中的列表类型正确
    如果使用GetX,Controller内的customerList需定义为:
final customerList = <CustomerElement>[].obs;

修改完成后,customerController.customerList[index]将返回单个CustomerElement对象,完全匹配CardList组件的参数要求,类型错误即可解决。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 13:42:22