Flutter加载API数据到DropdownButton时出现TypeError问题求助
错误原因
你遇到的_TypeError (type '_InternalLinkedHashMap<String, dynamic>' is not a subtype of type 'List<String>'),核心问题是数据结构解析错误:
- API返回的是包含
categories数组的JSON对象(Map),但你直接把整个Map赋值给了List类型的_dataMenu,导致类型不匹配。 - 构建Dropdown选项时,错误地尝试访问每个数据项的
categories字段,但单个数据项是分类对象,不存在这个字段,应该用strCategory。
分步解决方案
1. 修正JSON解析逻辑
修改数据请求方法,提取JSON中categories对应的数组赋值给_dataMenu:
void getCategories() async { final response = await http.get(Uri.parse(_baseUrl)); if (response.statusCode == 200) { var listData = jsonDecode(response.body); setState(() { // 只取categories数组部分 _dataMenu = listData['categories']; }); } else { print('请求失败,状态码:${response.statusCode}'); } }
(建议把方法名从getProvince改成getCategories,更贴合功能)
2. 修正Dropdown选项构建逻辑
每个_dataMenu里的元素是单个分类对象,要显示的是strCategory字段:
DropdownButton( hint: const Text("选择菜单"), value: _valMenu, items: _dataMenu.map((category) { return DropdownMenuItem( child: Text(category['strCategory']), value: category['strCategory'], ); }).toList(), onChanged: (value) { setState(() { _valMenu = value as String?; }); }, isExpanded: true, // 避免选项过长显示不全 ),
3. 可选:添加类型安全(推荐)
创建分类模型类,避免动态类型的潜在问题:
class Category { final String idCategory; final String strCategory; final String strCategoryThumb; final String strCategoryDescription; Category({ required this.idCategory, required this.strCategory, required this.strCategoryThumb, required this.strCategoryDescription, }); factory Category.fromJson(Map<String, dynamic> json) { return Category( idCategory: json['idCategory'], strCategory: json['strCategory'], strCategoryThumb: json['strCategoryThumb'], strCategoryDescription: json['strCategoryDescription'], ); } }
然后修改变量类型和解析逻辑:
// 把_dataMenu的类型改为List<Category> List<Category> _dataMenu = []; void getCategories() async { final response = await http.get(Uri.parse(_baseUrl)); if (response.statusCode == 200) { var listData = jsonDecode(response.body); setState(() { _dataMenu = (listData['categories'] as List) .map((item) => Category.fromJson(item)) .toList(); }); } } // Dropdown部分更新为 items: _dataMenu.map((category) { return DropdownMenuItem( child: Text(category.strCategory), value: category.strCategory, ); }).toList(),
完整修正后的代码
import 'package:flutter/material.dart'; import 'package:http/http.dart' as http; import 'dart:convert'; void main() => runApp(const MaterialApp( home: HomeScreen(), )); class HomeScreen extends StatefulWidget { const HomeScreen({super.key}); @override _HomeScreenState createState() => _HomeScreenState(); } class _HomeScreenState extends State<HomeScreen> { final String _baseUrl = "https://www.themealdb.com/api/json/v1/1/categories.php"; String? _valMenu; List<dynamic> _dataMenu = []; void getCategories() async { final response = await http.get(Uri.parse(_baseUrl)); if (response.statusCode == 200) { var listData = jsonDecode(response.body); setState(() { _dataMenu = listData['categories']; }); } else { print('请求失败,状态码:${response.statusCode}'); } } @override void initState() { super.initState(); getCategories(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text("Dropdown Menu Button JSON")), body: Padding( padding: const EdgeInsets.all(16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: <Widget>[ DropdownButton( hint: const Text("选择菜单"), value: _valMenu, items: _dataMenu.map((category) { return DropdownMenuItem( child: Text(category['strCategory']), value: category['strCategory'], ); }).toList(), onChanged: (value) { setState(() { _valMenu = value as String?; }); }, isExpanded: true, ), Text( "你选择了菜单 $_valMenu", style: const TextStyle( color: Colors.black, fontSize: 20, fontWeight: FontWeight.bold), ) ], ), ), ); } }
内容的提问来源于stack exchange,提问作者sharon
相关产品推荐
相关产品推荐

