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

Flutter/Dart中如何处理HTTP请求内容并将响应转为可用列表?

问题:将HTTP响应体转换为实体类列表并使用变量

打印的HTTP响应体

I/flutter (30828): {"firstName":"Georgee","lastName":"Contructed","userID":256,"month":8,"year":2022,"cardBills":[{"serial":"281929282881","value":4.8150,"vat":1.1556,"total":5.9706,"energy":0},{"serial":"281929282881","value":1.0567,"vat":0.2536,"total":1.3103,"energy":0}],"cardBillsTotal":[{"serial":"281929282881","value":5.8717,"vat":1.4092,"total":7.2809,"energy":0}]}

当前代码实现

页面中的相关方法

initState() {
  fetch();
}

List<Evsebill> parseBills(String responseBody) {
  final parsed = jsonDecode(responseBody)['cardBills'].cast<Map<String, dynamic>>();

  return parsed.map<Evsebill>((json) => Evsebill.fromJson(json)).toList();
}

Future<List<Evsebill>> fetch() async {
  String? token = await this.storage.read(key: "token");
  Map<String, String> headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
    "Authorization": "Bearer " + (token ?? ""),
  };
  final response = await http.get(Uri.parse(this.serverIP + ':' + this.serverPort + '/user/contractedChargeTransactions?month=8&year=2022'), headers: headers);

  // Use the compute function to run parsePhotos in a separate isolate.
  print(response.body);
  return parseBills(response.body);
}

Evsebill实体类

class Evsebill {
  final int serial;
  final double value;
  final double vat;
  final double total;
  final int energy;
 const Evsebill({
    required this.serial,
    required this.value,
    required this.vat,
    required this.total,
    required this.energy
  });
  factory Evsebill.fromJson(Map<String, dynamic> json) {
    return Evsebill(
      serial: json['serial'] as int,
      value: json['value']as double,
      vat: json['vat']as double,
      total: json['total']as double,
      energy: json['energy']as int,
    );
  }
}

问题分析与修复方案

你的代码会抛出类型转换错误,核心原因是HTTP响应里的serial字段是字符串类型(例如"281929282881"),但实体类中serial定义为int类型,直接强转as int会失败。以下是具体修复和使用方案:

1. 修正实体类的类型转换逻辑

有两种可选方案:

  • 方案一:将serial改为字符串类型(若不需要用该字段做数值计算):
    class Evsebill {
      final String serial; // 修改为String类型
      final double value;
      final double vat;
      final double total;
      final int energy;
     const Evsebill({
        required this.serial,
        required this.value,
        required this.vat,
        required this.total,
        required this.energy
      });
      factory Evsebill.fromJson(Map<String, dynamic> json) {
        return Evsebill(
          serial: json['serial'] as String, // 对应字符串类型
          value: json['value']as double,
          vat: json['vat']as double,
          total: json['total']as double,
          energy: json['energy']as int,
        );
      }
    }
    
  • 方案二:保留int类型,将字符串转为整数:
    factory Evsebill.fromJson(Map<String, dynamic> json) {
      return Evsebill(
        serial: int.parse(json['serial']), // 字符串转整数
        value: json['value']as double,
        vat: json['vat']as double,
        total: json['total']as double,
        energy: json['energy']as int,
      );
    }
    
    若serial可能为空或非数字字符串,建议增加异常处理:int.tryParse(json['serial']) ?? 0

2. 正确获取并使用列表数据

可以通过状态管理或FutureBuilder来渲染列表,示例如下:

List<Evsebill>? _bills;

@override
void initState() {
  super.initState();
  fetch().then((bills) {
    setState(() {
      _bills = bills;
    });
  });
}

@override
Widget build(BuildContext context) {
  return _bills == null 
      ? const CircularProgressIndicator()
      : ListView.builder(
          itemCount: _bills!.length,
          itemBuilder: (context, index) {
            final bill = _bills![index];
            return ListTile(
              title: Text('单号: ${bill.serial}'),
              subtitle: Text('总金额: ${bill.total.toStringAsFixed(2)}'),
            );
          },
        );
}

3. 优化JSON解析(可选)

使用compute函数在单独的isolate中解析JSON,避免阻塞UI线程:

Future<List<Evsebill>> fetch() async {
  String? token = await this.storage.read(key: "token");
  Map<String, String> headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
    "Authorization": "Bearer " + (token ?? ""),
  };
  final response = await http.get(Uri.parse('${this.serverIP}:${this.serverPort}/user/contractedChargeTransactions?month=8&year=2022'), headers: headers);

  // 后台线程解析JSON
  return compute(parseBills, response.body);
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 12:50:16