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

Flutter中如何用Data Model及GET请求处理嵌套JSON数据?

解决Flutter中FutureBuilder结合ListView.builder展示嵌套JSON数据的问题

问题分析

你的代码存在以下关键错误:

  • 数据模型不匹配:生成的模型类是Temperatures和Datum,但代码中误用了Product和Data,导致解析失败
  • JSON解析逻辑错误:直接从顶层JSON的data字段生成列表,未先解析包含result和data的顶层对象
  • UI展示逻辑错误:试图从列表项中获取顶层字段result,且未正确访问Datum类的属性

修正步骤

1. 完善数据模型的JSON解析方法

给生成的模型类添加fromJson工厂方法,确保JSON能正确转为对象,同时修正类型错误:

class Temperatures {
  final String result;
  final List<Datum> data;

  Temperatures({
    required this.result,
    required this.data,
  });

  factory Temperatures.fromJson(Map<String, dynamic> json) {
    return Temperatures(
      result: json['result'],
      data: List<Datum>.from(json['data'].map((x) => Datum.fromJson(x))),
    );
  }
}

class Datum {
  final int id;
  final String lucasTvsPartNo;
  final String partImage;
  final String filterType;
  final String customerPartNo;
  final String model;
  final String modelImage;
  final String segment;
  final String descriptions;
  final String oemName;
  final String oemImage;
  final dynamic oemPartNo;
  final double listPrice;
  final double mrpPrice; // 原JSON中MRPPrice是浮点型,修正int为double
  final int masterCartonSize;

  Datum({
    required this.id,
    required this.lucasTvsPartNo,
    required this.partImage,
    required this.filterType,
    required this.customerPartNo,
    required this.model,
    required this.modelImage,
    required this.segment,
    required this.descriptions,
    required this.oemName,
    required this.oemImage,
    required this.oemPartNo,
    required this.listPrice,
    required this.mrpPrice,
    required this.masterCartonSize,
  });

  factory Datum.fromJson(Map<String, dynamic> json) {
    return Datum(
      id: json['Id'],
      lucasTvsPartNo: json['LucasTvsPartNo'],
      partImage: json['PartImage'],
      filterType: json['FilterType'],
      customerPartNo: json['CustomerPartNo'],
      model: json['Model'],
      modelImage: json['ModelImage'],
      segment: json['Segment'],
      descriptions: json['Descriptions'],
      oemName: json['OEMName'],
      oemImage: json['OEMImage'],
      oemPartNo: json['OEMPartNo'],
      listPrice: json['ListPrice'].toDouble(),
      mrpPrice: json['MRPPrice'].toDouble(),
      masterCartonSize: json['MasterCartonSize'],
    );
  }
}

2. 修正数据获取方法

修改getData方法,正确解析整个JSON结构,返回Temperatures对象:

Future<Temperatures> getData() async {
  var url = Uri.parse('http://35.154.214.176/LucasfilterAPI/api/Values/GetPricelist');
  var response = await http.get(url, headers: {
    "Accept": "application/json",
    "content-type": "application/json"
  });

  if (response.statusCode == 200) {
    return Temperatures.fromJson(json.decode(response.body));
  } else {
    throw Exception('加载数据失败,状态码:${response.statusCode}');
  }
}

3. 修正UI展示逻辑

在FutureBuilder中正确获取data列表,展示Datum类的具体字段:

@override
Widget build(BuildContext context) {
  return Scaffold(
    appBar: AppBar(title: const Text('产品列表')),
    body: FutureBuilder<Temperatures>(
      future: _futureData,
      builder: (context, snapshot) {
        switch (snapshot.connectionState) {
          case ConnectionState.waiting:
            return const Center(child: CircularProgressIndicator());
          case ConnectionState.done:
            if (snapshot.hasError) {
              return Center(child: Text('错误:${snapshot.error}'));
            }
            if (!snapshot.hasData) {
              return const Center(child: Text('无数据'));
            }
            List<Datum> products = snapshot.data!.data;
            return ListView.builder(
              padding: const EdgeInsets.all(8),
              itemCount: products.length,
              itemBuilder: (context, index) {
                final product = products[index];
                return Card(
                  margin: const EdgeInsets.symmetric(vertical: 4),
                  child: ListTile(
                    title: Text(
                      product.model,
                      style: const TextStyle(fontWeight: FontWeight.bold),
                    ),
                    subtitle: Column(
                      crossAxisAlignment: CrossAxisAlignment.start,
                      mainAxisSize: MainAxisSize.min,
                      children: [
                        Text('过滤器类型:${product.filterType}'),
                        Text('Lucas零件号:${product.lucasTvsPartNo}'),
                        Text('MRP:₹${product.mrpPrice} | 标价:₹${product.listPrice}'),
                      ],
                    ),
                    leading: SizedBox(
                      width: 50,
                      height: 50,
                      child: Image.network(
                        'http://35.154.214.176/LucasfilterAPI/${product.partImage}',
                        fit: BoxFit.cover,
                        errorBuilder: (_, __, ___) => const Icon(Icons.image),
                      ),
                    ),
                  ),
                );
              },
            );
          default:
            return const Center(child: Text('加载中...'));
        }
      },
    ),
  );
}

完整修正后的代码

import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;

class Temperatures {
  final String result;
  final List<Datum> data;

  Temperatures({
    required this.result,
    required this.data,
  });

  factory Temperatures.fromJson(Map<String, dynamic> json) {
    return Temperatures(
      result: json['result'],
      data: List<Datum>.from(json['data'].map((x) => Datum.fromJson(x))),
    );
  }
}

class Datum {
  final int id;
  final String lucasTvsPartNo;
  final String partImage;
  final String filterType;
  final String customerPartNo;
  final String model;
  final String modelImage;
  final String segment;
  final String descriptions;
  final String oemName;
  final String oemImage;
  final dynamic oemPartNo;
  final double listPrice;
  final double mrpPrice;
  final int masterCartonSize;

  Datum({
    required this.id,
    required this.lucasTvsPartNo,
    required this.partImage,
    required this.filterType,
    required this.customerPartNo,
    required this.model,
    required this.modelImage,
    required this.segment,
    required this.descriptions,
    required this.oemName,
    required this.oemImage,
    required this.oemPartNo,
    required this.listPrice,
    required this.mrpPrice,
    required this.masterCartonSize,
  });

  factory Datum.fromJson(Map<String, dynamic> json) {
    return Datum(
      id: json['Id'],
      lucasTvsPartNo: json['LucasTvsPartNo'],
      partImage: json['PartImage'],
      filterType: json['FilterType'],
      customerPartNo: json['CustomerPartNo'],
      model: json['Model'],
      modelImage: json['ModelImage'],
      segment: json['Segment'],
      descriptions: json['Descriptions'],
      oemName: json['OEMName'],
      oemImage: json['OEMImage'],
      oemPartNo: json['OEMPartNo'],
      listPrice: json['ListPrice'].toDouble(),
      mrpPrice: json['MRPPrice'].toDouble(),
      masterCartonSize: json['MasterCartonSize'],
    );
  }
}

class Home extends StatefulWidget {
  const Home({super.key});

  @override
  State<Home> createState() => _HomeState();
}

class _HomeState extends State<Home> {
  late Future<Temperatures> _futureData;

  @override
  void initState() {
    super.initState();
    _futureData = getData();
  }

  Future<Temperatures> getData() async {
    var url = Uri.parse('http://35.154.214.176/LucasfilterAPI/api/Values/GetPricelist');
    var response = await http.get(url, headers: {
      "Accept": "application/json",
      "content-type": "application/json"
    });

    if (response.statusCode == 200) {
      return Temperatures.fromJson(json.decode(response.body));
    } else {
      throw Exception('加载数据失败,状态码:${response.statusCode}');
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('产品列表')),
      body: FutureBuilder<Temperatures>(
        future: _futureData,
        builder: (context, snapshot) {
          switch (snapshot.connectionState) {
            case ConnectionState.waiting:
              return const Center(child: CircularProgressIndicator());
            case ConnectionState.done:
              if (snapshot.hasError) {
                return Center(child: Text('错误:${snapshot.error}'));
              }
              if (!snapshot.hasData) {
                return const Center(child: Text('无数据'));
              }
              List<Datum> products = snapshot.data!.data;
              return ListView.builder(
                padding: const EdgeInsets.all(8),
                itemCount: products.length,
                itemBuilder: (context, index) {
                  final product = products[index];
                  return Card(
                    margin: const EdgeInsets.symmetric(vertical: 4),
                    child: ListTile(
                      title: Text(
                        product.model,
                        style: const TextStyle(fontWeight: FontWeight.bold),
                      ),
                      subtitle: Column(
                        crossAxisAlignment: CrossAxisAlignment.start,
                        mainAxisSize: MainAxisSize.min,
                        children: [
                          Text('过滤器类型:${product.filterType}'),
                          Text('Lucas零件号:${product.lucasTvsPartNo}'),
                          Text('MRP:₹${product.mrpPrice} | 标价:₹${product.listPrice}'),
                        ],
                      ),
                      leading: SizedBox(
                        width: 50,
                        height: 50,
                        child: Image.network(
                          'http://35.154.214.176/LucasfilterAPI/${product.partImage}',
                          fit: BoxFit.cover,
                          errorBuilder: (_, __, ___) => const Icon(Icons.image),
                        ),
                      ),
                    ),
                  );
                },
              );
            default:
              return const Center(child: Text('加载中...'));
          }
        },
      ),
    );
  }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 01:07:07