Flutter嵌套对象Snapshot始终为空:如何正确获取Registration嵌套数据?
我看了你的代码,发现几个关键问题导致snapshot.data一直为空,咱们一步步来解决:
核心问题分析
你的API返回的是单个Profile对象(包含id、ProfilePic和registration数组),但你的getCadres函数却试图把整个响应直接转换成List<Registration>,这完全不匹配JSON结构,所以解析失败,最终导致snapshot.data为空。另外你的Registration数据模型也漏了JSON里的字段,咱们逐个修复:
1. 完善Registration数据模型
JSON里的registration项包含reg_no、cadre、cadre_text三个字段,但你的模型只定义了regNo,先补上缺失的字段:
class Registration { Registration({ required this.regNo, required this.cadre, required this.cadreText, }); String regNo; String cadre; String cadreText; factory Registration.fromJson(Map<String, dynamic> json) => Registration( regNo: json["reg_no"], cadre: json["cadre"], cadreText: json["cadre_text"], ); Map<String, dynamic> toJson() => { "reg_no": regNo, "cadre": cadre, "cadre_text": cadreText, }; }
2. 修正getCadres的JSON解析逻辑
先把API响应解析成Profile对象,再从中提取registration列表,而不是直接把整个响应转成List<Registration>:
Future<List<Registration>> getCadres() async { var url = Uri.parse('https://xxx.co.ke/api/auth/user'); var idNo = Globals.idNumber; var indexNo = Globals.indexNo; var response = await http.post(url, body: {"IdNumber": '$idNo', "IndexNo": '$indexNo'}); // 先解析为Profile对象 Profile profile = Profile.fromJson(json.decode(response.body)); // 返回Profile中的registration列表 return profile.registration; }
3. 初始化Future并修复ListView嵌套问题
你声明了late Future<List<Registration>> _cadre;但没有初始化,要在initState里赋值;另外嵌套在SingleChildScrollView里的ListView需要设置shrinkWrap: true和禁止内部滚动,否则会出现高度冲突:
late Future<List<Registration>> _cadre; @override void initState() { super.initState(); // 初始化Future,调用接口获取数据 _cadre = getCadres(); } @override Widget build(BuildContext context) { return SingleChildScrollView( physics: AlwaysScrollableScrollPhysics(), child: FutureBuilder<List<Registration>>( future: _cadre, builder: (context, snapshot) { // 分状态处理:加载中、错误、空数据、正常数据 if (snapshot.connectionState == ConnectionState.waiting) { return Text('Loading...'); } else if (snapshot.hasError) { return Text('请求出错:${snapshot.error}'); } else if (!snapshot.hasData || snapshot.data!.isEmpty) { return Text('暂无注册信息'); } else { List<Registration> allCadres = snapshot.data!; print(allCadres); return ListView.builder( // 关键:适配外层滚动视图 shrinkWrap: true, physics: NeverScrollableScrollPhysics(), // 必须设置itemCount,避免无限循环构建 itemCount: allCadres.length, itemBuilder: (BuildContext context, int index) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ SizedBox(width: 16), // 替换自定义的16.width为标准组件 Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( allCadres[index].cadreText, style: boldTextStyle(size: 12, color: mlColorRed), ), ], ).expand() ], ), SizedBox(height: 16), // 替换自定义的paddingBottom为标准组件 ], ); }, ); } }, ), ); }
额外注意事项
- 一定要处理错误状态:原来的代码只判断了无数据的情况,加上
hasError和connectionState的判断,能帮你快速排查请求失败的原因。 ListView.builder必须设置itemCount,否则会无限调用itemBuilder,导致性能问题甚至崩溃。- 如果你的
16.width、.paddingBottom是自定义扩展方法,确保它们能正常工作,否则替换成Flutter标准的SizedBox和Padding组件。
内容的提问来源于stack exchange,提问作者tharnos_nos
相关产品推荐
相关产品推荐

