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

Flutter搜索API数据无法显示ListView,类型转换错误求助

搜索功能API数据无法显示的问题排查

问题场景

我是Flutter新手,在实现搜索功能时,API已返回正常JSON数据,但ListView无法加载显示,同时抛出以下类型错误:

Expected a value of type '(String, dynamic) => MapEntry<dynamic, dynamic>', but got one of type '(dynamic) => SearchModel$'

API返回的JSON片段

{
  "konten_gambar": null,
  "konten_gambar2": null,
  "konten_gambar3": null,
  "konten_deskripsi": null,
  "konten_syarat": null,
  "konten_ketentuan": null,
  "konten_fasilitas": null,
  "konten_promosi_gambar": null,
  "konten_promosi_text": null,
  "konten_sk": null,
  "konten_status": null,
  "konten_update": null,
  "konten_approval": null,
  "konten_url": "/danakonven",
  "file_path": null,
  "konten_deskripsi2": null,
  "konten_deskripsi3": null,
  "file_path2": null,
  "file_path3": null
}

错误信息

Expected a value of type '(String, dynamic) => MapEntry<dynamic, dynamic>', but got one of type '(dynamic) => SearchModel$'

源码

model.dart

import 'dart:convert';

List<SearchModel> searchModelFromJson(String str) => List<SearchModel>.from(
    // ignore: always_specify_types
    json.decode(str).map((x) => SearchModel.fromJson(x)));

String searchModelJson(List<SearchModel> data) =>
    json.encode(List<dynamic>.from(data.map((SearchModel x) => x.toJson())));

class SearchModel {
  SearchModel({
    this.kontenId,
    this.kontenParent,
    this.kontenUrut,
    this.kategoriId,
    this.kontenSimulasi,
    this.kontenSukuBunga,
    required this.kontenMenu,
    this.kontenJudul,
    this.kontenSubjudul,
    this.kontenGambar,
    this.kontenGambar2,
    this.kontenGambar3,
    this.kontenDeskripsi,
    this.kontenSyarat,
    this.kontenKetentuan,
    this.kontenFasilitas,
    this.kontenPromosiGambar,
    this.kontenPromosiText,
    this.kontenSk,
    this.kontenStatus,
    this.kontenUpdate,
    this.kontenApproval,
    this.kontenUrl,
    this.filePath,
    this.kategoriNama,
  });
  factory SearchModel.fromJson(Map<String, dynamic> json) => SearchModel(
        kontenId: json['konten_id'],
        kontenParent: json['konten_parent'],
        kontenUrut: json['konten_urut'],
        kategoriId: json['kategori_id'],
        kontenSimulasi: json['konten_simulasi'],
        kontenSukuBunga: json['konten_suku_bunga'],
        kontenMenu: json['konten_menu'],
        kontenJudul: json['konten_judul'],
        kontenSubjudul: json['konten_subjudul'],
        kontenGambar: json['konten_gambar'],
        kontenGambar2: json['konten_gambar2'],
        kontenGambar3: json['konten_gambar3'],
        kontenDeskripsi: json['konten_deskripsi'],
        kontenSyarat: json['konten_syarat'],
        kontenKetentuan: json['konten_ketentuan'],
        kontenFasilitas: json['konten_fasilitas'],
        kontenPromosiGambar: json['konten_promosi_gambar'],
        kontenPromosiText: json['konten_promosi_text'],
        kontenSk: json['konten_sk'],
        kontenStatus: json['konten_status'],
        kontenUpdate: json['konten_update'],
        kontenApproval: json['konten_approval'],
        kontenUrl: json['konten_url'],
        filePath: json['file_path'],
        kategoriNama: json['kategori_nama'],
      );

  dynamic kontenId;
  dynamic kontenParent;
  dynamic kontenUrut;
  dynamic kategoriId;
  dynamic kontenSimulasi;
  dynamic kontenSukuBunga;
  String kontenMenu;
  dynamic kontenJudul;
  dynamic kontenSubjudul;
  dynamic kontenGambar;
  dynamic kontenGambar2;
  dynamic kontenGambar3;
  dynamic kontenDeskripsi;
  dynamic kontenSyarat;
  dynamic kontenKetentuan;
  dynamic kontenFasilitas;
  dynamic kontenPromosiGambar;
  dynamic kontenPromosiText;
  dynamic kontenSk;
  dynamic kontenStatus;
  dynamic kontenUpdate;
  dynamic kontenApproval;
  dynamic kontenUrl;
  dynamic filePath;
  dynamic kategoriNama;

  Map<String, dynamic> toJson() => {
        'konten_id': kontenId,
        'konten_parent': kontenParent,
        'konten_urut': kontenUrut,
        'kategori_id': kategoriId,
        'konten_simulasi': kontenSimulasi,
        'konten_suku_bunga': kontenSukuBunga,
        'konten_menu': kontenMenu,
        'konten_judul': kontenJudul,
        'konten_subjudul': kontenSubjudul,
        'konten_gambar': kontenGambar,
        'konten_gambar2': kontenGambar2,
        'konten_gambar3': kontenGambar3,
        'konten_deskripsi': kontenDeskripsi,
        'konten_syarat': kontenSyarat,
        'konten_ketentuan': kontenKetentuan,
        'konten_fasilitas': kontenFasilitas,
        'konten_promosi_gambar': kontenPromosiGambar,
        'konten_promosi_text': kontenPromosiText,
        'konten_sk': kontenSk,
        'konten_status': kontenStatus,
        'konten_update': kontenUpdate,
        'konten_approval': kontenApproval,
        'konten_url': kontenUrl,
        'file_path': filePath,
        'kategori_nama': kategoriNama,
      };
}

apiservice.dart

class SearchService {
  Future<SearchModel> searchMenu(String kontenMenu) async {
    try {
      final String apiUrl = '${baseUrl}search/$kontenMenu';
      final http.Response response = await httpClient.get(
        Uri.parse(apiUrl),
        // ignore: always_specify_types
        headers: {
          'Content-Type': 'application/json',
          'Accept': 'application/json',
        },
      );

      debugPrint(response.body);

      if (response.statusCode == 200 || response.statusCode == 201) {
        // ignore: always_specify_types
        final it = json.decode(response.body);
        final List<SearchModel> list =
            // ignore: always_specify_types
            it.map((item) => SearchModel.fromJson(item))[0].toList();

     

问题排查与修复

1. API服务层核心错误

  • 返回类型不匹配:searchMenu方法声明返回Future<SearchModel>,但实际要处理的是列表数据,应改为Future<List<SearchModel>>。
  • 解析逻辑错误:it.map((item) => SearchModel.fromJson(item))返回的是可迭代对象,直接加[0].toList()会把第一个SearchModel实例当成列表处理,触发类型转换错误。

修复后的apiservice.dart片段:

class SearchService {
  // 修改返回类型为列表
  Future<List<SearchModel>> searchMenu(String kontenMenu) async {
    try {
      final String apiUrl = '${baseUrl}search/$kontenMenu';
      final http.Response response = await httpClient.get(
        Uri.parse(apiUrl),
        headers: {
          'Content-Type': 'application/json',
          'Accept': 'application/json',
        },
      );

      debugPrint(response.body);

      if (response.statusCode == 200 || response.statusCode == 201) {
        final dynamic it = json.decode(response.body);
        // 若API返回的是包含数组的对象(如{"data": [...]}),需改为it['data'].map(...)
        final List<SearchModel> list = List<SearchModel>.from(
          it.map((item) => SearchModel.fromJson(item))
        );
        return list;
      } else {
        throw Exception('请求失败');
      }
    } catch (e) {
      rethrow;
    }
  }
}

2. Model类必填字段问题

从API返回的JSON看,缺少konten_menu字段,但Model中该字段被标记为required,会导致解析时抛出空值异常。需修改为可选字段并设置默认值:

// 修改构造函数参数,去掉required
SearchModel({
  this.kontenId,
  this.kontenParent,
  this.kontenUrut,
  this.kategoriId,
  this.kontenSimulasi,
  this.kontenSukuBunga,
  this.kontenMenu,
  this.kontenJudul,
  // ...其他参数
});

// fromJson中处理空值
factory SearchModel.fromJson(Map<String, dynamic> json) => SearchModel(
      // ...其他字段
      kontenMenu: json['konten_menu'] ?? '', // 给默认空字符串
      // ...其他字段
    );

3. 错误根源总结

  • 服务层返回类型与实际数据结构不匹配,解析逻辑错误触发类型转换异常。
  • Model中必填字段kontenMenu在API返回中缺失,会引发空值错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 05:40:37