从PHP API获取数据填充Flutter Table并修复length调用在null上的错误
问题修复方案
报错原因
你遇到的NoSuchMethodError: The getter 'length' was called on null报错由以下几个问题共同导致:
- fetch方法返回值类型混乱:同时返回
List<Model>和Table组件,类型不匹配 - 数据解析逻辑错误:json解析后未调用
Model.fromJson做实体转换,直接赋值给List<Model>类型变量导致数据为空 - 未定义变量直接调用:代码中使用的
toList变量未初始化,本身为null,调用map方法时内部会访问length属性触发报错 - 字段不匹配:原有TableCell中使用的
sn/name/address/phone等字段在你的Model实体类中不存在
修复实现
第一步:修正数据请求方法
请求方法只负责数据获取和解析,不处理UI渲染:
// 只负责请求数据,返回List<Model> Future<List<Model>> fetchData() async { String apiurl = "替换为你的PHP接口实际地址"; var response = await http.post(Uri.parse(apiurl), body: { 'username': email // 传入实际的email参数 }); if(response.statusCode == 200) { // 如果API返回的是多个Model组成的数组,用下面的写法 List jsonList = jsonDecode(response.body); return jsonList.map((item) => Model.fromJson(item)).toList(); // 如果API返回的是单个Model对象(和你给出的示例结构一致),改成下面的写法: // return [Model.fromJson(jsonDecode(response.body))]; } else { return []; } }
第二步:用FutureBuilder异步渲染Table
在Widget的build方法中使用FutureBuilder加载异步数据,同时在每行末尾添加箭头标识:
@override Widget build(BuildContext context) { return FutureBuilder<List<Model>>( future: fetchData(), builder: (context, snapshot) { // 加载中状态 if (snapshot.connectionState == ConnectionState.waiting) { return const CircularProgressIndicator(); } // 加载出错/无数据状态 if (!snapshot.hasData || snapshot.data!.isEmpty) { return const Text("暂无数据"); } List<Model> dataList = snapshot.data!; return Table( border: TableBorder.all(width:1, color:Colors.black45), children: [ // 表头行,可根据实际需要展示的字段调整 const TableRow( children: [ TableCell(child: Padding(padding: EdgeInsets.all(5), child: Text("ID"))), TableCell(child: Padding(padding: EdgeInsets.all(5), child: Text("项目描述"))), TableCell(child: Padding(padding: EdgeInsets.all(5), child: Text("状态"))), TableCell(child: Padding(padding: EdgeInsets.all(5), child: Text("申请日期"))), TableCell(child: Padding(padding: EdgeInsets.all(5), child: Text("操作"))), ] ), // 遍历数据生成数据行 ...dataList.map((model) { return TableRow( children: [ TableCell(child: Padding(padding: const EdgeInsets.all(5), child: Text(model.id ?? ""))), TableCell(child: Padding(padding: const EdgeInsets.all(5), child: Text(model.bnDesc ?? ""))), TableCell(child: Padding(padding: const EdgeInsets.all(5), child: Text(model.reqStatus ?? ""))), TableCell(child: Padding(padding: const EdgeInsets.all(5), child: Text(model.reqDate?.toString().substring(0,10) ?? ""))), // 末尾列添加箭头标识 TableCell(child: Padding(padding: const EdgeInsets.all(5), child: Icon(Icons.arrow_forward_ios, size: 16))), ] ); }).toList() ], ); } ); }
补充说明
可根据业务需要调整Table展示的字段,直接取model对应的属性即可;如果需要展示关联的tender列表数据,可在对应TableCell中嵌套多Widget实现。
内容的提问来源于stack exchange,提问作者jerome
相关产品推荐
相关产品推荐

