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

Flutter中API响应转List<ChildDataModel>类型转换异常排查

解决Flutter中API响应转嵌套Freezed模型的类型转换异常

核心问题分析

你遇到的List<dynamic> is not a subtype of type List<ChildDataModel>异常,本质是Dio返回的动态列表无法直接强转为强类型列表——即便用map做了转换,若没正确处理Iterable到强类型List的转换,或是Freezed模型的序列化方法调用有误,都会触发这个错误。

分步解决方案

1. 确保Freezed模型的序列化配置正确

先检查你的Freezed模型是否正确生成了fromJson方法,且配置了json_serializable依赖。

示例修正后的Freezed模型代码:

import 'package:freezed_annotation/freezed_annotation.dart';

part 'parent_data_model.freezed.dart';
part 'parent_data_model.g.dart';

@freezed
class ParentDataModel with _$ParentDataModel {
  const factory ParentDataModel({
    required List<ChildDataModel> children,
    // 其他业务字段...
  }) = _ParentDataModel;

  // 必须保留该方法,用于JSON反序列化
  factory ParentDataModel.fromJson(Map<String, dynamic> json) =>
      _$ParentDataModelFromJson(json);
}

@freezed
class ChildDataModel with _$ChildDataModel {
  const factory ChildDataModel({
    required String id,
    required String name,
    // 其他业务字段...
  }) = _ChildDataModel;

  factory ChildDataModel.fromJson(Map<String, dynamic> json) =>
      _$ChildDataModelFromJson(json);
}

注意:写完代码后必须运行flutter pub run build_runner build,重新生成序列化相关的代码文件,确保_$XXXFromJson方法正确生成。

2. 修正Riverpod中的响应转换逻辑

不要直接对List<dynamic>强转,而是通过map逐个将JSON对象转为ChildDataModel,再调用toList()生成强类型列表。分两种场景处理:

场景1:API直接返回ChildDataModel数组

final childListProvider = FutureProvider<List<ChildDataModel>>((ref) async {
  final dioHelper = ref.watch(dioHelperProvider);
  final response = await dioHelper.get('/api/children');
  
  // 正确转换流程:遍历动态列表→逐个转模型→生成强类型List
  return (response.data as List<dynamic>)
      .map((jsonItem) => ChildDataModel.fromJson(jsonItem as Map<String, dynamic>))
      .toList(); // 关键:toList()会生成明确的List<ChildDataModel>
});

场景2:API返回包含嵌套列表的ParentDataModel格式JSON

final parentDataProvider = FutureProvider<ParentDataModel>((ref) async {
  final dioHelper = ref.watch(dioHelperProvider);
  final response = await dioHelper.get('/api/parent');
  
  // 直接用ParentDataModel的fromJson方法,Freezed会自动处理嵌套的children列表
  return ParentDataModel.fromJson(response.data as Map<String, dynamic>);
});

这里Freezed的序列化逻辑会自动调用ChildDataModel.fromJson处理嵌套的子列表,无需手动遍历转换。

3. Dio请求方法的补充检查

确保你的DioHelper不要提前对响应数据做不必要的类型转换:

class DioHelper {
  final Dio _dio;

  DioHelper(this._dio);

  Future<Response> get(String path) async {
    final response = await _dio.get(path);
    // 直接返回原始响应,不要提前强转data的类型
    return response;
  }
}

常见错误排查点

  • 忘记运行build_runner:如果_$XXXFromJson方法不存在,会直接导致转换失败。
  • map转换时未强转JSON类型:API返回的每个子项是JSON对象,必须明确强转为Map<String, dynamic>后再调用fromJson。
  • 直接强转动态列表:比如response.data as List<ChildDataModel>,Dart不允许这种未验证元素类型的强转操作。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 09:10:07