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

Flutter加载API数据到DropdownButton时出现TypeError问题求助

解决Flutter DropdownButton加载API数据的类型不匹配错误

错误原因

你遇到的_TypeError (type '_InternalLinkedHashMap<String, dynamic>' is not a subtype of type 'List<String>'),核心问题是数据结构解析错误:

  1. API返回的是包含categories数组的JSON对象(Map),但你直接把整个Map赋值给了List类型的_dataMenu,导致类型不匹配。
  2. 构建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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 17:30:52