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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 15:37:42