Flutter中用FutureBuilder实现下拉框加载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('没有可用的食堂数据'); } }, ), ), ); } }
关键修改点说明
- 添加
.toList():在map(...)后面加上.toList(),把MappedListIterable转成List<DropdownMenuItem<String>>,满足DropdownButton的参数要求。 - 完善状态处理:在
FutureBuilder中分别处理了waiting(加载中)、hasError(加载失败)、hasData(加载成功)和空数据的情况,避免了因snapshot.data为null导致的崩溃。 - URL适配:把
http.get的字符串URL改成Uri.parse(),符合Flutter最新版本的API要求(旧版本直接传字符串也能运行,但新版本推荐用Uri)。
内容的提问来源于stack exchange,提问作者sayantank
相关产品推荐
相关产品推荐

