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

Flutter StreamBuilder展示API数据出现重复问题求助

Flutter StreamBuilder展示数据重复问题的原因及解决方法

错误原因

  • 全局列表重复累加:clientList作为成员变量,每次调用getClientList都会执行clientList.add(...),且没有先清空旧数据;再加上getClientsStream用1ms间隔无限循环调用getClientList,导致列表被反复填充,数据越积越多。
  • 重复触发数据获取:既在initState中调用了getClientList,又通过Stream的无限循环重复调用,双重叠加导致初始数据就重复。
  • StreamBuilder未使用快照数据:展示用的clientList和Stream返回的数据脱节,每次Stream更新时,旧的clientList已经积累了多轮数据,自然出现重复。

解决方法

1. 重置列表,避免累加

在getClientList中添加新数据前先清空旧列表:

Future<List<DisplayClients>> getClientList() async {
  String email = widget.email;
  final response = await http.get(Uri.parse(api));
  if (response.statusCode == 200) {
    final parsed = json.decode(response.body).cast<Map<String, dynamic>>();

    var list = parsed
        .map<DisplayClients>((json) => DisplayClients.fromMap(json))
        .toList();
    print('clientList length: ${list.length}');

    // 关键:先清空旧数据,再添加新数据
    clientList.clear();
    for (var i = 0; i < list.length; i++) {
      clientList.add(AlphabetSearchModel(
          title: list[i].name,
          subtitle: list[i].email,
          phoneNumber: list[i].phoneNumber));
    }

    return list;
  } else {
    throw Exception('Failed to load album');
  }
}

2. 优化Stream调用逻辑

如果不需要实时刷新,直接用Stream.fromFuture一次性获取数据即可;如果需要定时刷新,设置合理的间隔(比如30秒),不要用1ms的高频循环:

// 一次性获取数据的Stream
Stream<List<DisplayClients>> getClientsStream() {
  return Stream.fromFuture(getClientList());
}

// 或者定时刷新(示例:30秒一次)
Stream<List<DisplayClients>> getClientsStream() async* {
  yield await getClientList();
  while (true) {
    await Future.delayed(Duration(seconds: 30));
    yield await getClientList();
  }
}

3. 移除initState中的重复调用

既然已经通过Stream获取数据,删掉initState里的getClientList()调用,避免初始数据重复。

4. (可选)直接用快照数据生成列表

彻底抛弃全局clientList,在StreamBuilder中直接根据快照数据生成展示列表,从根源避免全局变量的问题:

StreamBuilder<List<DisplayClients>>(
  stream: getClientsStream(),
  builder: (context, snapshot) {
    if (snapshot.hasData) {
      // 直接从快照数据生成AlphabetSearchModel列表
      final clientList = snapshot.data!.map((client) => AlphabetSearchModel(
        title: client.name,
        subtitle: client.email,
        phoneNumber: client.phoneNumber,
      )).toList();

      return SizedBox(
        height: MediaQuery.of(context).size.height * 0.7,
        child: AlphabetSearchView.modelList(
          list: clientList,
          buildItem: (context, index, item) {
            // 原有item构建代码保持不变
            return Padding(
              padding: const EdgeInsets.symmetric(vertical: 6),
              child: Card(...),
            );
          },
        ),
      );
    }
    // 替换空容器为加载提示,提升用户体验
    return Center(child: CircularProgressIndicator());
  },
)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 20:10:49