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

Flutter解析TheMealDB API数据时部分分类报Null转String类型错误

问题根因

报错直接原因是类型转换不匹配:接口返回的Null值被赋值给了声明为非空String类型的变量,本质是两个开发错误导致的:

  • 接口用错:当前调用的search.php?s=关键词是按餐品名称模糊搜索的接口,不是按分类拉取餐品的接口。传分类名作为搜索词时,返回结果不稳定:Vegan分类能正常展示只是巧合——刚好返回的所有Vegan相关餐品的字段都不为空;Beef分类下返回的餐品存在字段值为null的情况,直接触发类型错误。
  • 模型解析不规范:你贴出的Model代码是分类列表接口的解析逻辑,和页面中调用的餐品列表接口结构完全不匹配;且实际使用的Meal类未做空安全处理,所有字段都声明为非空String,也没做null值兜底,只要接口返回null就会直接崩溃。另外页面中Image.network直接传入未判空的图片地址,也存在崩溃风险。
修复方案

按以下步骤调整即可解决问题:

  • 替换为正确的分类餐品接口
    按分类筛选餐品的官方接口为https://www.themealdb.com/api/json/v1/1/filter.php?c=分类名,该接口会稳定返回指定分类下的所有餐品,不会返回多余的空字段。
  • 重写匹配接口的Model类,加入空值兜底
    不要混用不同接口的解析模型,针对分类餐品接口写对应解析逻辑,所有字段加入null兜底,避免类型错误:
    import 'dart:convert';
    
    MealsResponse mealsJsonFromJson(String str) => MealsResponse.fromJson(json.decode(str));
    
    class MealsResponse {
      MealsResponse({required this.meals});
    
      List<Meal> meals;
    
      factory MealsResponse.fromJson(Map<String, dynamic> json) => MealsResponse(
        // 无匹配结果时接口meals字段会返回null,这里直接兜底为空数组
        meals: json["meals"] == null 
          ? [] 
          : List<Meal>.from(json["meals"].map((x) => Meal.fromJson(x))),
      );
    }
    
    class Meal {
      Meal({
        required this.strMeal,
        required this.strMealThumb,
        required this.idMeal,
      });
    
      String strMeal;
      String strMealThumb;
      String idMeal;
    
      factory Meal.fromJson(Map<String, dynamic> json) => Meal(
        // 每个字段加空值兜底,null时赋值为空字符串,避免类型不匹配
        strMeal: json["strMeal"] ?? "",
        strMealThumb: json["strMealThumb"] ?? "",
        idMeal: json["idMeal"] ?? "",
      );
    }
    
  • 调整页面逻辑,增加加载态和错误兜底
    class _MealScreenState extends State<MealScreen> {
      List<Meal> mealsIn = [];
      bool isLoading = true;
    
      Future<void> getMealInside() async {
        Uri uri = Uri.parse(
            'https://www.themealdb.com/api/json/v1/1/filter.php?c=${widget.names}');
        final response = await http.get(uri);
    
        if (response.statusCode == 200) {
          final result = mealsJsonFromJson(response.body);
          mealsIn = result.meals;
        }
        isLoading = false;
        setState(() {});
      }
    
      @override
      void initState() {
        super.initState();
        getMealInside();
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text(widget.names),
          ),
          body: isLoading
            ? const Center(child: CircularProgressIndicator())
            : ListView.separated(
                itemBuilder: (context, index) {
                  final mealsOut = mealsIn[index];
                  return ListTile(
                    title: Text(mealsOut.strMeal.isEmpty ? "暂无餐品名称" : mealsOut.strMeal),
                    leading: mealsOut.strMealThumb.isEmpty
                      ? const Icon(Icons.fastfood, size: 50)
                      : Image.network(
                          mealsOut.strMealThumb,
                          width: 50,
                          height: 50,
                          fit: BoxFit.cover,
                          // 图片加载失败兜底
                          errorBuilder: (_, __, ___) => const Icon(Icons.broken_image, size:50),
                        ),
                  );
                },
                separatorBuilder: (context, index) => const Divider(),
                itemCount: mealsIn.length,
              ),
        );
      }
    }
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 02:24:26