Flutter请求公共API转换JSON为Dart对象出现NoSuchMethodError求助
问题核心原因
你看到的object_patch.dart抛出的NoSuchMethodError是Dart VM的统一异常入口,本质是业务代码中JSON解析的类型、结构和接口实际返回格式完全不匹配,和底层VM实现无关,具体错误点:
- 接口返回的顶层是单个包含
Search字段的JSON对象,不是Map列表,你在fetchMovie中把顶层解码结果强转为Map列表后直接调用map遍历,会触发方法不存在的异常。 Movie.fromJson中直接将原始JSON数组传给List<Search>.from(),没有对数组内的原始Map元素逐次调用Search.fromJson做类型转换,后续访问元素属性时会触发空引用、方法不存在的报错。- FutureBuilder定义的泛型、取值逻辑和实际返回结构错位,错误地将单个Movie对象当成Movie列表遍历访问。
修复方案
1. 重构模型类的JSON转换逻辑
补全数组元素的逐次转换,使用factory构造函数简化写法,避免空值隐患:
class Movie { List<Search> search; Movie({required this.search}); factory Movie.fromJson(Map<String, dynamic> json) { final rawSearchList = json['Search'] as List; return Movie( search: rawSearchList.map((item) => Search.fromJson(item as Map<String, dynamic>)).toList(), ); } } class Search { final String imdbID; final String title; final String year; final String poster; Search({ required this.imdbID, required this.title, required this.year, required this.poster, }); factory Search.fromJson(Map<String, dynamic> json) { return Search( imdbID: json['imdbID'] as String, title: json['Title'] as String, year: json['Year'] as String, poster: json['Poster'] as String, ); } }
2. 修正网络请求的返回结构
去掉错误的列表强转逻辑,对齐接口返回的单个对象结构:
Future<Movie> fetchMovie() async { // 新版本http包要求传入Uri对象,不要直接传字符串 final response = await http.get(Uri.parse('https://fake-movie-database-api.herokuapp.com/api?s=batman')); // 顶层解码结果直接转为Map,不需要强转为列表 final body = jsonDecode(response.body) as Map<String, dynamic>; return Movie.fromJson(body); }
3. 修正界面渲染逻辑
对齐数据层级,补全加载、错误状态的判断,避免空指针:
class _HomePageState extends State<HomePage> { @override Widget build(BuildContext context) { return FutureBuilder<Movie>( future: fetchMovie(), builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.waiting) { return const Center(child: CircularProgressIndicator()); } if (snapshot.hasError) { return Center(child: Text('请求失败: ${snapshot.error}')); } if (snapshot.hasData) { final movieData = snapshot.data!; return ListView.builder( // 直接使用搜索结果的实际长度,不要硬编码itemCount itemCount: movieData.search.length, itemBuilder: (context, index) { final currentItem = movieData.search[index]; return Container( margin: const EdgeInsets.symmetric(horizontal: 25, vertical: 16), height: 200, color: Colors.blue, child: Center( child: Text(currentItem.title), ), ); }, ); } return const SizedBox(); }, ); } }
避坑提示
- 不要被
object_patch.dart的报错路径误导,这个文件是Dart VM的内置实现,所有类型不匹配、调用不存在方法的异常最终都会路由到这里,和你修改Dart SDK源码没有关系。 List<自定义类>.from()方法只能转换已经是自定义类类型的列表,不会自动将原始Map转为自定义类实例,必须手动逐元素调用fromJson方法。- 取值时必须严格对齐接口JSON的层级关系,不要自行脑补嵌套结构。
内容的提问来源于stack exchange,提问作者Sela404
相关产品推荐
相关产品推荐

