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

Flutter嵌套模型列表所有元素均存最后添加项的原因排查

问题原因及解决方案

问题现象

循环加载队伍数据并添加到listaEquipesGeral后,列表中所有元素的equipe属性都指向最后一次加载的listaAtletaEquipe数据,所有项的equipe内容完全一致。

核心原因

Dart中列表属于引用类型,你的代码存在两个关键问题:

  • 全局的listaAtletaEquipe是同一个列表实例,每次调用_loadEquipe时只是执行clear()清空原有内容,再添加新数据,内存地址始终不变。
  • 循环中_reg.equipe = listaAtletaEquipe是把这个全局列表的引用赋值给每个TabelaListaEquipes对象,所有_reg的equipe属性都指向同一个内存地址的列表。后续每次修改listaAtletaEquipe的内容,所有引用它的对象都会同步更新,最终所有项都显示最后一次加载的数据。

修复方案

方案1:重构_loadEquipe,返回新的列表实例

不再依赖全局的listaAtletaEquipe,每次加载时创建新列表,从根源避免引用复用:

// 移除全局的listaAtletaEquipe定义
Future<List<TabelaInscricoes>> _loadEquipe(String equipId) async {
  setState(() {
    carregandoEquipe = true;
  });

  List<TabelaInscricoes> listaAtletaEquipe = []; // 每次调用创建新列表
  TabelaInscricoes _result = TabelaInscricoes();
  CollectionReference _dbCollection = FirebaseFirestore.instance
      .collection('campeonatos')
      .doc(resultSelect.campId)
      .collection('divisoes')
      .doc(resultSelect.divId)
      .collection('equipes')
      .doc(equipId)
      .collection('atletas');

  await _dbCollection.orderBy('pos2', descending: false).get().then((QuerySnapshot querySnapshot) async {
    if (querySnapshot.docs.isNotEmpty) {
      querySnapshot.docs.forEach((element) {
        _result = TabelaInscricoes.fromJson(element.data()! as Map<String, dynamic>);
        if (_result.campId == resultSelect.campId && _result.divId == resultSelect.divId) {
          _result.id = element.id;
          _result.filePath = "";
          listaAtletaEquipe.add(_result);
        }
      });

      // 填充运动员信息
      for (int x = 0; x < listaAtletaEquipe.length; x++) {
        for (int y = 0; y < listaAtletas.length; y++) {
          if (listaAtletaEquipe[x].atletaId.toString() == listaAtletas[y].id.toString()) {
            listaAtletaEquipe[x].nome = listaAtletas[y].nome;
            listaAtletaEquipe[x].fotoNome = listaAtletas[y].fotoNome;
            listaAtletaEquipe[x].filePath = listaAtletas[y].filePath;
            listaAtletaEquipe[x].dataN = listaAtletas[y].dataN;
            listaAtletaEquipe[x].fone1 = listaAtletas[y].fone1;
            listaAtletaEquipe[x].fone2 = listaAtletas[y].fone2;
            listaAtletaEquipe[x].nTitulo = listaAtletas[y].nTitulo;
            listaAtletaEquipe[x].info = listaAtletas[y].info;
            listaAtletaEquipe[x].email = listaAtletas[y].email;
          }
        }
      }

      // 获取图片URL
      for (int x = 0; x < listaAtletaEquipe.length; x++) {
        if (listaAtletaEquipe[x].fotoNome.toString().isNotEmpty) {
          String url = await MyStorage.getUrl(context, "atletas/${listaAtletaEquipe[x].fotoNome.toString()}");
          listaAtletaEquipe[x].filePath = url;
        }
      }
    }
    setState(() {
      carregandoEquipe = false;
    });
  });

  return listaAtletaEquipe;
}

然后修改循环代码:

for (int x=0; x<listaEquipes.length; x++) {
  List<TabelaInscricoes> equipeData = await _loadEquipe(listaEquipes[x].id.toString());
  TabelaListaEquipes _reg = TabelaListaEquipes();
  _reg.equipeId = listaEquipes[x].id.toString();
  _reg.equipe = equipeData; // 赋值新创建的列表实例
  listaEquipesGeral.add(_reg);
}

方案2:保留全局列表,赋值时创建副本

如果不想修改_loadEquipe的返回值,可在循环中给_reg.equipe赋值时,创建当前listaAtletaEquipe的副本,避免引用同一实例:

for (int x=0; x<listaEquipes.length; x++) {
  await _loadEquipe(listaEquipes[x].id.toString());
  TabelaListaEquipes _reg = TabelaListaEquipes();
  _reg.equipeId = listaEquipes[x].id.toString();
  _reg.equipe = List.from(listaAtletaEquipe); // 创建列表副本
  listaEquipesGeral.add(_reg);
}

注意:方案2仅当TabelaInscricoes是不可变对象时完全安全,如果TabelaInscricoes后续会被修改,建议给TabelaInscricoes添加copyWith方法实现深拷贝,逐个复制属性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 08:25:29