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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 05:20:41