
本文档旨在指导开发者如何从 PHP API 获取数据,并使用 Flutter 的 Table 组件将数据动态地填充到表格中。文章将涵盖数据模型的定义、API 数据的获取、JSON 解析以及表格的构建,同时提供代码示例和注意事项,帮助开发者解决常见的 NoSuchMethodError 问题。
数据模型定义
首先,我们需要定义一个 Dart 类来映射从 PHP API 获取的 JSON 数据。根据提供的 JSON 示例,我们已经有了 Model 和 Tender 类。确保这些类中的字段类型与 API 返回的数据类型一致。例如,如果 API 返回的某个字段可能为 null,则在 Dart 类中将其声明为可空类型(例如 String? 或 dynamic)。
class Model {
Model({
this.id,
this.goodsRef,
this.loyer,
this.bnCode,
this.loyeeNo,
this.contactName,
this.contactTel,
this.bnDesc,
this.reqStatus,
this.eMail,
this.comments,
this.tender,
this.reqDate,
this.sscOffice,
});
final String? id;
final int? goodsRef;
final String? loyer;
final String? bnCode;
final int? loyeeNo;
final dynamic contactName;
final dynamic contactTel;
final String? bnDesc;
final String? reqStatus;
final dynamic eMail;
final String? comments;
final List? tender;
final DateTime? reqDate;
final dynamic sscOffice;
factory Model.fromJson(Map json) => Model(
id: json["\u0024id"] == null ? null : json["\u0024id"],
goodsRef: json["goods_ref"] == null ? null : json["goods_ref"],
loyer: json["loyer"] == null ? null : json["loyer"],
bnCode: json["bn_code"] == null ? null : json["bn_code"],
loyeeNo: json["loyee_no"] == null ? null : json["loyee_no"],
contactName: json["contact_name"],
contactTel: json["contact_tel"],
bnDesc: json["bn_desc"] == null ? null : json["bn_desc"],
reqStatus: json["req_status"] == null ? null : json["req_status"],
eMail: json["e_mail"],
comments: json["comments"] == null ? null : json["comments"],
tender: json["tender"] == null ? null : List.from(json["tender"].map((x) => Tender.fromJson(x))),
reqDate: json["req_date"] == null ? null : DateTime.tryParse(json["req_date"]),
sscOffice: json["ssc_office"],
);
Map toJson() => {
"\u0024id": id == null ? null : id,
"goods_ref": goodsRef == null ? null : goodsRef,
"loyer": loyer == null ? null : loyer,
"bn_code": bnCode == null ? null : bnCode,
"loyee_no": loyeeNo == null ? null : loyeeNo,
"contact_name": contactName,
"contact_tel": contactTel,
"bn_desc": bnDesc == null ? null : bnDesc,
"req_status": reqStatus == null ? null : reqStatus,
"e_mail": eMail,
"comments": comments == null ? null : comments,
"tender": tender == null ? null : List.from(tender!.map((x) => x.toJson())),
"req_date": reqDate == null ? null : reqDate!.toIso8601String(),
"ssc_office": sscOffice,
};
}
class Tender {
Tender({
this.id,
this.goodsRef,
this.inNo,
this.tenderNo,
this.closingDate,
});
final String? id;
final int? goodsRef;
final int? inNo;
final String? tenderNo;
final String? closingDate;
factory Tender.fromJson(Map json) => Tender(
id: json["\u0024id"] == null ? null : json["\u0024id"],
goodsRef: json["goods_ref"] == null ? null : json["goods_ref"],
inNo: json["in_no"] == null ? null : json["in_no"],
tenderNo: json["tender_no"] == null ? null : json["tender_no"],
closingDate: json["closing_date"] == null ? null : json["closing_date"],
);
Map toJson() => {
"\u0024id": id == null ? null : id,
"goods_ref": goodsRef == null ? null : goodsRef,
"in_no": inNo == null ? null : inNo,
"tender_no": tenderNo == null ? null : tenderNo,
"closing_date": closingDate == null ? null : closingDate,
};
} 注意:
- 将可能为 null 的字段类型改为可空类型,例如 String?。
- 使用 DateTime.tryParse 来解析日期字符串,避免解析失败。
- 在 toJson 方法中,对可空列表进行非空判断。
从 PHP API 获取数据
使用 http 包从 PHP API 获取数据。确保已在 pubspec.yaml 文件中添加了 http 依赖。
立即学习“PHP免费学习笔记(深入)”;
dependencies:
flutter:
sdk: flutter
http: ^0.13.5 # 确保使用最新版本然后,可以使用以下代码从 API 获取数据:
import 'dart:convert'; import 'package:http/http.dart' as http; Future> fetchItems(String email) async { String apiurl = "YOUR_API_ENDPOINT"; // 替换为你的 API 端点 var response = await http.post(Uri.parse(apiurl), body: { 'username': email //get the username text }); if (response.statusCode == 200) { // 使用 utf8.decode 处理中文乱码问题 final decodedBody = utf8.decode(response.bodyBytes); List
jsonResponse = jsonDecode(decodedBody); List model = jsonResponse.map((item) => Model.fromJson(item)).toList(); return model; } else { throw Exception('Failed to load data from API'); } }
注意:
- 将 YOUR_API_ENDPOINT 替换为你的实际 API 端点。
- 使用 utf8.decode(response.bodyBytes) 处理中文乱码问题。
- 使用 Model.fromJson(item) 将 JSON 数据转换为 Model 对象。
- 添加错误处理,当 API 请求失败时抛出异常。
构建 Flutter 表格
获取到数据后,就可以使用 Table 组件来显示数据。
import 'package:flutter/material.dart';
class MyTable extends StatefulWidget {
final String email;
const MyTable({Key? key, required this.email}) : super(key: key);
@override
_MyTableState createState() => _MyTableState();
}
class _MyTableState extends State {
late Future> _dataFuture;
@override
void initState() {
super.initState();
_dataFuture = fetchItems(widget.email);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Data Table')),
body: FutureBuilder>(
future: _dataFuture,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(child: CircularProgressIndicator());
} else if (snapshot.hasError) {
return Center(child: Text('Error: ${snapshot.error}'));
} else if (snapshot.hasData) {
return SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Table(
border: TableBorder.all(width: 1, color: Colors.black45),
columnWidths: const {
0: IntrinsicColumnWidth(),
1: IntrinsicColumnWidth(),
2: IntrinsicColumnWidth(),
3: IntrinsicColumnWidth(),
},
children: [
// 表头
TableRow(
children: [
TableCell(child: Center(child: Padding(padding: const EdgeInsets.all(8.0), child: const Text('Goods Ref')))),
TableCell(child: Center(child: Padding(padding: const EdgeInsets.all(8.0), child: const Text('Loyer')))),
TableCell(child: Center(child: Padding(padding: const EdgeInsets.all(8.0), child: const Text('BN Code')))),
TableCell(child: Center(child: Padding(padding: const EdgeInsets.all(8.0), child: const Text('BN Desc')))),
],
),
// 表格数据
...snapshot.data!.map((item) {
return TableRow(
children: [
TableCell(child: Center(child: Padding(padding: const EdgeInsets.all(8.0), child: Text(item.goodsRef?.toString() ?? '')))),
TableCell(child: Center(child: Padding(padding: const EdgeInsets.all(8.0), child: Text(item.loyer ?? '')))),
TableCell(child: Center(child: Padding(padding: const EdgeInsets.all(8.0), child: Text(item.bnCode ?? '')))),
TableCell(child: Center(child: Padding(padding: const EdgeInsets.all(8.0), child: Text(item.bnDesc ?? '')))),
],
);
}).toList(),
],
),
);
} else {
return const Center(child: Text('No data available'));
}
},
),
);
}
}
关键点:
- 使用 FutureBuilder 来处理异步数据加载。
- 在 Text 组件中使用 item.propertyName ?? '' 来处理可能为 null 的值,避免 NoSuchMethodError。
- 使用 SingleChildScrollView 包裹 Table 组件,以支持水平滚动。
- 添加表头,使表格更易于理解。
- 使用 IntrinsicColumnWidth 可以让单元格根据内容自动调整宽度。
解决 NoSuchMethodError
NoSuchMethodError: The getter 'length' was called on null 错误通常发生在尝试访问 null 值的属性时。例如,如果 nameone.sn 为 null,则 nameone.sn.length 会抛出此错误。
解决方法是在访问可能为 null 的属性之前,使用空值检查或空值合并运算符 ??。例如:
Text(nameone.sn ?? "") // 如果 nameone.sn 为 null,则显示空字符串
或者,可以使用条件判断:
Text(nameone.sn != null ? nameone.sn : "")
在上面的代码示例中,我们已经使用了空值合并运算符 ?? 来处理可能为 null 的值,从而避免了 NoSuchMethodError。
总结
本文档详细介绍了如何从 PHP API 获取数据并在 Flutter 中使用 Table 组件显示数据。通过定义数据模型、使用 http 包获取数据、解析 JSON 数据以及使用空值合并运算符处理 null 值,可以有效地构建动态表格并避免常见的错误。记住,在处理 API 数据时,始终要考虑数据可能为 null 的情况,并采取相应的措施来避免运行时错误。











