Flutter中FutureBuilder返回空列表,response.body数据正常问题排查
排查Flutter FutureBuilder返回空列表的问题
结合你描述的场景(接口返回数据正确但FutureBuilder始终拿空列表),从以下几个核心方向排查:
1. 确认JSON结构与Model解析的匹配性
首先检查接口返回的JSON层级,是否存在外层包裹对象而非直接返回数组。比如常见的接口结构:
{ "code": 200, "message": "success", "data": [{"id":1, "name":"GameA"}, {"id":2, "name":"GameB"}] }
如果你的Provider代码直接把整个响应体解析为数组,就会因为外层是Map而非List导致解析失败,最终返回空列表:
// 错误写法:直接解析整个响应 return List<GameModel>.from(jsonDecode(response.body).map((x) => GameModel.fromJson(x))); // 正确写法:先提取内层列表字段 final decoded = jsonDecode(response.body); return List<GameModel>.from(decoded['data'].map((x) => GameModel.fromJson(x)));
2. 检查GameModel的fromJson方法
确保Model的字段与JSON完全对应,包括字段名、数据类型:
- 字段名大小写/下划线是否一致:比如JSON里是
game_name,Model里不能写gameName(除非用@JsonKey(name: "game_name")注解) - 数据类型匹配:比如JSON里
id是数字类型,Model里不能用String接收 - 必填字段是否处理:如果JSON里有非空字段,Model里未正确赋值会导致解析失败,进而整个列表为空
示例错误写法:
class GameModel { final String name; GameModel({required this.name}); factory GameModel.fromJson(Map<String, dynamic> json) { return GameModel( name: json['gameName'], // JSON里实际是game_name,导致name为null ); } }
3. 排查Provider请求代码的异常处理
如果请求代码中吞掉了解析异常,会导致返回空列表而非抛出错误,难以定位问题:
// 错误写法:异常时直接返回空列表 Future<List<GameModel>> fetchGames() async { try { final response = await http.get(Uri.parse("your_url")); final decoded = jsonDecode(response.body); return List<GameModel>.from(decoded['data'].map((x) => GameModel.fromJson(x))); } catch (e) { print(e); // 务必打印错误信息 return []; // 这里返回空列表会掩盖问题 } }
建议异常时直接抛出,让FutureBuilder的snapshot.hasError捕获,方便排查:
catch (e) { print("解析错误:$e"); throw Exception("加载游戏列表失败:$e"); }
4. 检查FutureBuilder的使用是否合理
避免每次build时重新创建Future,导致请求重复触发、状态重置:
// 错误写法:每次build都调用fetchGames(),导致Future重置 FutureBuilder<List<GameModel>>( future: Provider.of<GameProvider>(context).fetchGames(), builder: (context, snapshot) { ... } ) // 正确写法:将Future存到State中 class _YourPageState extends State<YourPage> { late final Future<List<GameModel>> _gameFuture; @override void initState() { super.initState(); _gameFuture = Provider.of<GameProvider>(context, listen: false).fetchGames(); } @override Widget build(BuildContext context) { return FutureBuilder<List<GameModel>>( future: _gameFuture, builder: (context, snapshot) { ... } ); } }
内容的提问来源于stack exchange,提问作者Zhandaulet Zhaxylykuly
相关产品推荐
相关产品推荐

