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

Flutter中FutureBuilder与ListViewBuilder数据加载问题求助

解决Flutter中API返回列表无法获取length的问题

你当前的代码把API返回的结果列表当成了单个ResultModel对象来解析,所以snapshot.data是单个实例,自然没有length属性,也不能用[index]访问元素。以下是具体修复步骤:

1. 调整ResultModel类,添加列表解析方法

在原模型类中新增一个静态方法,用来将API返回的数组解析为ResultModel列表:

class ResultModel {
  int? examId;
  String? examName;
  int? examStream;
  String? createdAt;
  String? updatedAt;

  ResultModel(
      {this.examId,
      this.examName,
      this.examStream,
      this.createdAt,
      this.updatedAt});

  // 保留原单个对象解析方法
  ResultModel.fromJson(Map<String, dynamic> json) {
    examId = json['exam_id'];
    examName = json['exam_name'];
    examStream = json['exam_stream'];
    createdAt = json['created_at'];
    updatedAt = json['updated_at'];
  }

  // 新增:解析数组为ResultModel列表
  static List<ResultModel> fromJsonList(List<dynamic> jsonList) {
    return jsonList.map((json) => ResultModel.fromJson(json)).toList();
  }

  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = new Map<String, dynamic>();
    data['exam_id'] = this.examId;
    data['exam_name'] = this.examName;
    data['exam_stream'] = this.examStream;
    data['created_at'] = this.createdAt;
    data['updated_at'] = this.updatedAt;
    return data;
  }
}

2. 修改getResults方法,返回列表类型

将原方法的返回值从单个ResultModel改为List<ResultModel>,适配API返回的数组格式:

Future<List<ResultModel>> getResults() async {
  SharedPreferences prefs = await SharedPreferences.getInstance();
  var token = await prefs.getString('token');
  var response = await http.get(
    Uri.parse('http://localhost:8000/api/student/results'),
    headers: {
      'Accept': 'application/json',
      'Content-Type': 'application/x-www-form-urlencoded',
      'Authorization': "Bearer $token",
    },
  );
  // 将响应体解析为数组,再转成ResultModel列表
  return ResultModel.fromJsonList(jsonDecode(response.body));
}

3. 更新FutureBuilder和ListView代码

调整FutureBuilder的泛型类型,并用列表长度作为itemCount,正常访问列表元素:

@override
Widget build(BuildContext context) {
  return Scaffold(
    appBar: AppBar(title: const Text('My Results')),
    body: Padding(
      padding: const EdgeInsets.all(18.0),
      child: FutureBuilder<List<ResultModel>>(
        future: getResults(),
        builder: (context, snapshot) {
          if (snapshot.hasData) {
            return ListView.builder(
              // 使用列表长度作为itemCount
              itemCount: snapshot.data!.length,
              itemBuilder: (BuildContext context, int index) {
                final result = snapshot.data![index];
                return ListTile(
                  contentPadding: const EdgeInsets.all(5.0),
                  leading: const Icon(
                    Icons.menu_book,
                    color: Colors.blueAccent,
                  ),
                  // 正常访问模型属性
                  title: Text(result.examId.toString()),
                  subtitle: Text(result.examName ?? '无考试名称'),
                  trailing: const Icon(Icons.visibility),
                  onTap: () {
                    Navigator.push(context, MaterialPageRoute(builder: (context) => DetailResult()));
                  },
                );
              },
            );
          } else if (snapshot.hasError) {
            // 新增错误提示,方便调试
            return Center(child: Text('加载失败: ${snapshot.error}'));
          } else {
            return const Center(child: CircularProgressIndicator());
          }
        },
      ),
    ),
  );
}

额外优化建议

可以在initState中提前加载数据并存入状态变量,避免每次build都重复请求API:

List<ResultModel>? _results;

@override
void initState() {
  super.initState();
  _loadResults();
}

Future<void> _loadResults() async {
  final data = await getResults();
  setState(() {
    _results = data;
  });
}

// 后续FutureBuilder的future改为Future.value(_results),或直接判断_results状态

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 02:03:13