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

Flutter中用FutureBuilder实现下拉框加载API数据报错求助

解决Flutter DropdownButton结合FutureBuilder展示Django API数据的问题

嘿,我刚好碰到过类似的问题,咱们一步步来搞定它!

报错原因分析

你看到的这个类型不匹配错误,核心原因是:snapshot.data.map(...)返回的是Iterable类型,但DropdownButton的items参数要求的是List类型。只需要把这个Iterable转成List就能解决这个类型问题啦。另外,咱们还要处理FutureBuilder中数据加载的不同状态(加载中、加载失败、加载完成),避免空指针异常。

可运行的完整示例代码

下面是调整后的完整代码,包含所有必要的部分:

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

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Food Court Selector',
      theme: ThemeData(primarySwatch: Colors.blue),
      home: const FoodCourtDropdownPage(),
    );
  }
}

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

  @override
  State<FoodCourtDropdownPage> createState() => _FoodCourtDropdownPageState();
}

class _FoodCourtDropdownPageState extends State<FoodCourtDropdownPage> {
  String? selectedFc; // 选中的食堂名称

  // 实体类保持不变
  class FoodCourt {
    final String name;
    FoodCourt(this.name);
  }

  // 获取数据的方法保持不变
  Future<List<FoodCourt>> _getFoodCourt() async {
    var data = await http.get(Uri.parse("http://timetable-api-manipal.herokuapp.com/getfoodcourt"));
    var jsonData = json.decode(data.body);
    List<FoodCourt> fcs = [];
    for (var u in jsonData) {
      FoodCourt fc = FoodCourt(u["name"]);
      fcs.add(fc);
    }
    return fcs;
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Select Food Court')),
      body: Center(
        child: FutureBuilder<List<FoodCourt>>(
          future: _getFoodCourt(),
          builder: (context, snapshot) {
            // 处理加载中状态
            if (snapshot.connectionState == ConnectionState.waiting) {
              return const CircularProgressIndicator();
            }
            // 处理加载错误状态
            else if (snapshot.hasError) {
              return Text('加载失败: ${snapshot.error}');
            }
            // 处理数据加载完成状态
            else if (snapshot.hasData && snapshot.data!.isNotEmpty) {
              return DropdownButton<String>(
                hint: const Text("Select"),
                value: selectedFc,
                onChanged: (newValue) {
                  setState(() {
                    selectedFc = newValue;
                  });
                },
                // 关键修正:在map后调用.toList()转成List类型
                items: snapshot.data!.map((fc) {
                  return DropdownMenuItem<String>(
                    child: Text(fc.name),
                    value: fc.name,
                  );
                }).toList(), // 这里添加.toList()
              );
            }
            // 处理空数据状态
            else {
              return const Text('没有可用的食堂数据');
            }
          },
        ),
      ),
    );
  }
}

关键修改点说明

  1. 添加.toList():在map(...)后面加上.toList(),把MappedListIterable转成List<DropdownMenuItem<String>>,满足DropdownButton的参数要求。
  2. 完善状态处理:在FutureBuilder中分别处理了waiting(加载中)、hasError(加载失败)、hasData(加载成功)和空数据的情况,避免了因snapshot.data为null导致的崩溃。
  3. URL适配:把http.get的字符串URL改成Uri.parse(),符合Flutter最新版本的API要求(旧版本直接传字符串也能运行,但新版本推荐用Uri)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.13 08:37:54