Flutter中PaginatedDataTable无法加载API数据问题求助
问题:PaginatedDataTable无法加载数据,输出为null
API返回的JSON数据如下:
"data": { "list_item": [ { "item": "1", "item_date": "1669189813143566825", "item_id": "0", "item_info": {}, "item_status":"on" }] }
使用普通DataTable的TableSamleNew组件可以正常加载展示数据,但集成分页、排序、搜索的DataTableWithSortTest组件无法显示数据,输出为null。以下是两段组件代码:
可正常运行的普通DataTable代码
class TableSamleNew extends StatefulWidget { const TableSamleNew({Key? key}) : super(key: key); @override State<TableSamleNew> createState() => _TableSamleNewState(); } class _TableSamleNewState extends State<TableSamleNew> { final getListController = Get.put(GetListController()); late List<ListItem>? listItem=getListController.getListClient!.data!.listItem; @override Widget build(BuildContext context) { return Scaffold( body: GetBuilder<GetListController>( builder: (_) => getListController.isLoading ? const Padding( padding: EdgeInsets.only(top:50), child: Center(child: CircularProgressIndicator()), ): DataTable(columns: [ DataColumn(label: Text("1")), DataColumn(label: Text("1")), DataColumn(label: Text("1")), DataColumn(label: Text("1")), DataColumn(label: Text("1")) ],rows: listItem!.map<DataRow>((e) => DataRow(cells: [ DataCell(Text(e.itemInfo!.clientMobile.toString())), DataCell(Text(e.itemId.toString())), DataCell(Text(e.itemId.toString())), DataCell(Text("")), DataCell(Text("")), ])).toList()), ), ); } }
无法显示数据的PaginatedDataTable代码
class DataTableWithSortTest extends StatefulWidget { const DataTableWithSortTest({Key? key, required this.title}) : super(key: key); final String title; @override State<DataTableWithSortTest> createState() => _DataTableWithSortTestState(); } class _DataTableWithSortTestState extends State<DataTableWithSortTest> { final getListController = Get.put(GetListController()); late List<ListItem>? listItem=getListController.getListClient!.data!.listItem; bool sort = true; onsortColum(int columnIndex, bool ascending) { if (columnIndex == 0) { if (ascending) { listItem!.sort((a, b) => a.itemStatus!.compareTo(b.itemStatus!)); } else { listItem!.sort((a, b) => b.itemStatus!.compareTo(a.itemStatus!)); } } } @override void initState() { listItem = listItem!.cast<ListItem>(); super.initState(); } TextEditingController controller = TextEditingController(); @override Widget build(BuildContext context) { print(listItem); return Directionality( textDirection: TextDirection.rtl, child: Scaffold( body: SingleChildScrollView( child: Container( padding: const EdgeInsets.all(8.0), decoration: BoxDecoration( color: Theme.of(context).canvasColor, borderRadius: const BorderRadius.all(Radius.circular(10)), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ SizedBox( width: double.infinity, child: Theme( data: ThemeData.light() .copyWith(cardColor: Theme.of(context).canvasColor), child: PaginatedDataTable( sortColumnIndex: 0, sortAscending: sort, header: Container( padding: const EdgeInsets.all(5), decoration: BoxDecoration( border: Border.all( color: Colors.grey, ), borderRadius: BorderRadius.circular(12)), child: TextField( controller: controller, decoration: const InputDecoration( hintText: "search with name"), onChanged: (value) { setState(() { listItem = listItem! .where((element) => element.itemStatus!.contains(value)) .toList(); }); }, ), ), source: RowSource( listItem: listItem, count: listItem?.length, ), rowsPerPage: 5, columnSpacing: 5, columns: [ DataColumn( label: const Text( "1", style: TextStyle( fontWeight: FontWeight.w600, fontSize: 14), ), onSort: (columnIndex, ascending) { setState(() { sort = !sort; }); // onsortColum(columnIndex, ascending); }), const DataColumn( label: Text( "2", style: TextStyle( fontWeight: FontWeight.w600, fontSize: 14), ), ), const DataColumn( label: Text( "3", style: TextStyle( fontWeight: FontWeight.w600, fontSize: 14), ), ), const DataColumn( label: Text( "4", style: TextStyle( fontWeight: FontWeight.w600, fontSize: 14), ), ), const DataColumn( label: Text( "5", style: TextStyle( fontWeight: FontWeight.w600, fontSize: 14), ), ), ], ), )), const SizedBox(height: 20), ], ), ), )), ); } } class RowSource extends DataTableSource { var listItem; final count; RowSource({ required this.listItem, required this.count, }); @override DataRow? getRow(int index) { if (index < rowCount) { return recentFileDataRow(listItem![index]); } else return null; } @override bool get isRowCountApproximate => false; @override int get rowCount => count; @override int get selectedRowCount => 0; } DataRow recentFileDataRow(var listItem) { return const DataRow( cells: [ DataCell(Text("")), DataCell(Text("")), DataCell(Text("")), DataCell(Text("")), DataCell(Text("")), ], ); }
问题排查与修复方案
1. 数据初始化时机错误
正常组件用GetBuilder监听控制器状态,确保数据加载完成后才渲染表格;而有问题的组件在成员变量直接赋值listItem,此时控制器可能还没拿到API数据,导致初始值为null。
修复:在GetBuilder内部获取数据,同时增加加载状态判断:
class _DataTableWithSortTestState extends State<DataTableWithSortTest> { final getListController = Get.put(GetListController()); List<ListItem>? listItem; List<ListItem>? originalList; // 保存原始数据,用于搜索恢复 bool sort = true; @override Widget build(BuildContext context) { return Directionality( textDirection: TextDirection.rtl, child: Scaffold( body: GetBuilder<GetListController>( builder: (_) { if (getListController.isLoading) { return const Padding( padding: EdgeInsets.only(top:50), child: Center(child: CircularProgressIndicator()), ); } // 从控制器获取最新数据 originalList = getListController.getListClient?.data?.listItem; listItem ??= originalList; return SingleChildScrollView( // 原布局代码... ); }, ), ), ); } }
2. 数据行完全未使用传入数据
recentFileDataRow返回的是固定空内容的const DataRow,根本没用到传入的listItem数据,导致表格无内容。
修复:根据数据生成对应单元格:
DataRow recentFileDataRow(ListItem listItem) { return DataRow( cells: [ DataCell(Text(listItem.itemStatus ?? "")), DataCell(Text(listItem.itemId ?? "")), DataCell(Text(listItem.item ?? "")), DataCell(Text(listItem.itemDate ?? "")), DataCell(Text(listItem.itemInfo?.clientMobile?.toString() ?? "")), ], ); }
3. 搜索逻辑丢失原始数据
搜索时直接覆盖listItem,导致后续无法恢复原始数据,且未通知数据源更新。
修复:基于原始数据过滤,同时通知数据源刷新:
onChanged: (value) { setState(() { if (value.isEmpty) { listItem = originalList; } else { listItem = originalList?.where((element) => element.itemStatus?.toLowerCase().contains(value.toLowerCase()) ?? false) .toList(); } // 通知数据源更新 RowSource(listItem: listItem, count: listItem?.length).notifyListeners(); }); }
4. 排序逻辑未生效且未通知更新
onSort回调注释了排序方法调用,且排序后未通知DataTableSource刷新数据。
修复:启用排序方法,并通知数据源更新:
onSort: (columnIndex, ascending) { setState(() { sort = ascending; onsortColum(columnIndex, ascending); // 通知数据源刷新 RowSource(listItem: listItem, count: listItem?.length).notifyListeners(); }); }
5. 初始化时强制cast可能引发空指针
initState中listItem = listItem!.cast<ListItem>();如果listItem初始为null,会直接崩溃,应该去掉这个不必要的cast,或者先判空。
修复:删除该cast语句,因为getListController.getListClient!.data!.listItem已经是List<ListItem>?类型。
内容的提问来源于stack exchange,提问作者Iman Yarahmadi
相关产品推荐
相关产品推荐

