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

Flutter:将FutureBuilder转换为StreamBuilder实现数据持续更新

把FutureBuilder改为StreamBuilder实现实时数据更新

1. 创建StreamController管理数据流

在你的State类中定义一个StreamController,用来发射最新的列表数据(使用broadcast支持多订阅):

final StreamController<List<Map<String, dynamic>>> _itemsStreamController = StreamController.broadcast();

2. 改造数据获取函数

将原来的fetch函数改为能获取数据并发送到Stream的函数,同时处理异常:

Future<void> _fetchAndEmitData() async {
  try {
    final session = await account.get();
    final sessionid = session.$id;
    final documentList = await databases.listDocuments(
      databaseId: '123456789',
      collectionId: '123456789',
      queries: [
        Query.orderDesc('\$id'),
        Query.limit(25),
      ],
    );
    final documents = documentList.documents;

    // 转换数据格式
    final items = documents.map((doc) {
      final epTitle = doc.data['epTitle'];
      final epNo = doc.data['epNo'];
      final epDuration = doc.data['epDuration'];

      return {
        ...doc.data,
        'epTitle': epTitle,
        'epNo': epNo,
        'epDuration': epDuration,
      };
    }).toList();

    // 将数据发送到Stream
    _itemsStreamController.add(items);
  } catch (e) {
    // 发送错误信息到Stream
    _itemsStreamController.addError(e);
  }
}

3. 初始化和关闭Stream

在initState中触发首次数据获取,并选择合适的更新方式:

方式一:定时刷新(适合无实时推送的场景)

@override
void initState() {
  super.initState();
  // 首次加载数据
  _fetchAndEmitData();
  // 每30秒自动刷新一次,可按需调整间隔
  Timer.periodic(const Duration(seconds: 30), (_) => _fetchAndEmitData());
}

方式二:实时订阅Appwrite文档变化(推荐)

利用Appwrite的实时API,数据库文档变化时自动刷新:

@override
void initState() {
  super.initState();
  // 首次加载数据
  _fetchAndEmitData();
  // 订阅文档变化,有更新时重新获取数据
  databases.subscribeDocuments(
    databaseId: '123456789',
    collectionId: '123456789',
    queries: [
      Query.orderDesc('\$id'),
      Query.limit(25),
    ],
    callback: (_) => _fetchAndEmitData(),
  );
}

页面销毁时关闭StreamController,避免内存泄漏:

@override
void dispose() {
  _itemsStreamController.close();
  super.dispose();
}

4. 替换FutureBuilder为StreamBuilder

使用StreamBuilder监听Stream并构建UI:

StreamBuilder<List<Map<String, dynamic>>>(
  stream: _itemsStreamController.stream,
  builder: (context, snapshot) {
    if (snapshot.connectionState == ConnectionState.waiting) {
      return const Text('waiting');
    } else if (snapshot.hasError) {
      checkInternet();
      return Text('${snapshot.error}');
    } else if (snapshot.hasData) {
      final items = snapshot.data!;
      return ListView.builder(
        itemCount: items.length,
        itemBuilder: (context, index) {
          final item = items[index];
          // 替换为你的列表项UI
          return ListTile(
            title: Text(item['epTitle'] ?? '无标题'),
            subtitle: Text('第${item['epNo']}集 | 时长${item['epDuration']}'),
          );
        },
      );
    } else {
      return const Text('暂无数据');
    }
  },
)

关键说明

  • 原代码中FutureBuilder的snapshot.length是错误写法,StreamBuilder通过snapshot.data!获取列表数据。
  • 使用broadcast类型的StreamController可支持多个Widget订阅同一数据流。
  • 实时订阅方式比定时轮询更高效,优先推荐使用Appwrite的实时API。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 22:05:53