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

Flutter中不使用StreamBuilder、Widget及.listen如何从Stream获取数据?

在不使用StreamBuilder和.listen的前提下,给PaginatedDataTable的DataTableSource传入Stream数据

问题背景

使用PaginatedDataTable组件时,需要将从Cloud Firestore读取的Stream数据传入自定义的MyData类(继承自DataTableSource)。参考示例是在MyData内部生成数据,但实际数据从外部Stream获取,且不能使用StreamBuilder(或其他Widget)和.listen方法。

现有代码

原StreamBuilder使用代码

StreamBuilder<List<Model>>(
  stream: stream,
  builder: (context, snapshot) {
    return snapshot.data == null
        ? Container()
        : PaginatedDataTable(
            source: MyData(list: snapshot.data!),
            columns: [
              DataColumn(
                label: Text(
                  "Name",
                  maxLines: 1,
                  overflow: TextOverflow.ellipsis,
                ),
              ),
              DataColumn(
                label: Text(
                  "Email",
                  maxLines: 1,
                  overflow: TextOverflow.ellipsis,
                ),
              ),
            ],
            columnSpacing: 20,
            horizontalMargin: 10,
            rowsPerPage: 10,
            showCheckboxColumn: false,
          );
  },
),

原MyData类代码

class MyData extends DataTableSource {
  MyData({required this.list}) : super();
  final List<Model> list;

  @override
  bool get isRowCountApproximate => false;
  @override
  int get rowCount => list.length;
  @override
  int get selectedRowCount => 0;
  @override
  DataRow getRow(int index) {
    return DataRow(
      cells: [
        DataCell(
          Text(
            list[index].name,
          ),
        ),
        DataCell(
          Text(
            list[index].email,
          ),
        ),
      ],
    );
  }
}

解决方案

利用Dart的await for异步循环处理Stream数据,结合DataTableSource的notifyListeners()方法刷新表格,无需使用StreamBuilder或.listen:

修改后的MyData类

class MyData extends DataTableSource {
  // 直接接收Stream而非List
  MyData({required this.stream}) {
    // 初始化时启动Stream监听
    _initStreamListener();
  }
  final Stream<List<Model>> stream;
  List<Model> _dataList = [];

  // 异步初始化方法,用await for处理Stream
  Future<void> _initStreamListener() async {
    try {
      // 循环接收Stream的每个数据事件
      await for (final newData in stream) {
        _dataList = newData;
        // 通知表格数据更新,触发刷新
        notifyListeners();
      }
    } catch (e) {
      // 处理Stream可能出现的错误
      print('Stream error: $e');
    }
  }

  @override
  bool get isRowCountApproximate => false;
  @override
  int get rowCount => _dataList.length;
  @override
  int get selectedRowCount => 0;
  @override
  DataRow getRow(int index) {
    return DataRow(
      cells: [
        DataCell(Text(_dataList[index].name)),
        DataCell(Text(_dataList[index].email)),
      ],
    );
  }
}

修改后的PaginatedDataTable使用代码

无需再用StreamBuilder,直接传入Stream给MyData:

PaginatedDataTable(
  source: MyData(stream: stream),
  columns: [
    DataColumn(
      label: Text(
        "Name",
        maxLines: 1,
        overflow: TextOverflow.ellipsis,
      ),
    ),
    DataColumn(
      label: Text(
        "Email",
        maxLines: 1,
        overflow: TextOverflow.ellipsis,
      ),
    ),
  ],
  columnSpacing: 20,
  horizontalMargin: 10,
  rowsPerPage: 10,
  showCheckboxColumn: false,
),

说明

  • await for是Dart原生的异步循环语法,不属于Stream的.listen方法,符合需求。
  • 每次Stream推送新数据时,更新内部的_dataList并调用notifyListeners(),这是DataTableSource提供的方法,会自动触发PaginatedDataTable刷新行数据。
  • 注意处理Stream的错误和生命周期,确保在页面销毁时关闭Stream,避免内存泄漏。

内容的提问来源于stack exchange,提问作者My Car

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 00:25:19