【问题标题】:Preventing Flutter StreamBuilder from Duplicating Data in ListView防止 Flutter StreamBuilder 在 ListView 中复制数据
【发布时间】:2020-04-29 13:06:39
【问题描述】:

我遇到了 StreamBuilder 和 ListView 的问题。

我的初始构建按预期工作,从我的数据库加载所有节点并将它们添加到 ListView:

--节点1 --节点2 --节点3

但是,当向 DB(节点 4)添加新节点时,StreamBuilder 会识别更改并将整个节点列表附加到 ListView,从而导致重复数据:

--节点1 --节点2 --节点 3 --节点1 --节点2 --节点 3 --节点4


class _HomeScreenState extends State<HomeScreen> {
  DatabaseReference usersChatsRef =
      FirebaseDatabase().reference().child('users-chats');

  @override
  void initState() {
    super.initState();

    Stream<List<UsersChats>> getData(User currentUser) async* {
      var usersChatsStream = usersChatsRef.child(currentUser.uid).onValue;
      var foundChats = List<UsersChats>();

      await for (var userChatSnapshot in usersChatsStream) {
        Map dictionary = userChatSnapshot.snapshot.value;
        if (dictionary != null) {
          for (var dictItem in dictionary.entries) {
            UsersChats thisChat;
            if (dictItem.key != null) {
              thisChat = UsersChats.fromMap(dictItem);
            } else {
              thisChat = UsersChats();
            }
            foundChats.add(thisChat);
          }
        }

        yield foundChats;
      }
    }
  }

  @override
  Widget build(BuildContext context) {
    final user = Provider.of<User>(context);

    return Scaffold(
      appBar: AppBar(),
      body: StreamBuilder<List<UsersChats>>(
          stream: getData(user),
          builder:
              (BuildContext context, AsyncSnapshot<List<UsersChats>> snap) {
            if (snap.hasError || !snap.hasData)
              return Text('Error: ${snap.error}');
            switch (snap.connectionState) {
              case ConnectionState.waiting:
                return Text("Loading...");
              default:
                return ListView.builder(
                  itemCount: snap.data.length,
                  itemBuilder: (context, index) {
                    return ListTile(
                      title: Text(snap.data[index].id),
                      subtitle: Text(snap.data[index].lastUpdate),
                    );
                  },
                );
            }
          }),
    );
  }
}
class UsersChats {
  String id;
  String lastUpdate;

  UsersChats(
      {this.id,
      this.lastUpdate});

  factory UsersChats.fromMap(MapEntry<dynamic, dynamic> data) {
    return UsersChats(
        id: data.key ?? '',
        lastUpdate: data.value['lastUpdate'] ?? '');
  }
}

我在 build 方法之外引用流,因为我需要在流上执行多个异步函数(如本线程 How do I join data from two Firestore collections in Flutter? 中所述)。

任何帮助将不胜感激!

【问题讨论】:

  • 听起来usersChatsRef.child(currentUser.uid).onValue 在每次更改时都会发出整个列表,而不是只推送差异。这意味着您不必“添加”到foundChat,只需删除之前的列表即可。
  • 感谢您的快速回复!你知道我会如何修改getData 函数吗?一直在尝试不同的方法,但到目前为止没有任何运气。
  • 尝试在“等待”的第一行清除foundChats
  • 太棒了!做到了,非常感谢!!!
  • 剩下的唯一问题是,当我使用Navigator.push 并导航离开然后返回主屏幕时,ListView 的数据消失了。也许需要 StreamSubscription(正如您在此处概述的那样:stackoverflow.com/questions/54101589/…)?我正在努力添加这个,如果成功我会发布我的结果。

标签: firebase flutter firebase-realtime-database stream-builder


【解决方案1】:

发布工作代码。再次感谢雷米的提示!希望此代码对其他人有所帮助!

class _HomeScreenState extends State<HomeScreen> {
  DatabaseReference usersChatsRef =
      FirebaseDatabase().reference().child('users-chats');

  List<UsersChats> myChats = [];

  StreamSubscription _streamSubscription;

  @override
  void initState() {
    super.initState();

    _streamSubscription = getData().listen((data) {

      setState(() {
        myChats = data;
      });
    });

  }

  @override
  void dispose() {
    _streamSubscription?.cancel(); // don't forget to close subscription
    super.dispose();
  }


  Stream<List<UsersChats>> getData() async* {
    var usersChatsStream = usersChatsRef.child('userId').onValue;
    var foundChats = List<UsersChats>();

    await for (var userChatSnapshot in usersChatsStream) {
      foundChats.clear();
      Map dictionary = userChatSnapshot.snapshot.value;
      if (dictionary != null) {
        for (var dictItem in dictionary.entries) {
          UsersChats thisChat;
          if (dictItem.key != null) {
            thisChat = UsersChats.fromMap(dictItem);
          } else {
            thisChat = UsersChats();
          }
          foundChats.add(thisChat);
        }
      }

      yield foundChats;
    }
  }

  @override
  Widget build(BuildContext context) {
    final user = Provider.of<User>(context);

    return Scaffold(
      appBar: AppBar(),
      body: ListView.builder(
        itemCount: myChats.length,
        itemBuilder: (context, index) {
            title: Text(myChats[index].id),
            subtitle: Text(myChats[index].lastUpdate),
            onTap: () {
              Navigator.pushNamed(context, MessagesScreen.id);
            },
          );
        },
      ),
    );
  }
}


【讨论】:

    猜你喜欢
    • 2021-07-06
    • 2021-04-09
    • 2021-09-23
    • 1970-01-01
    • 2020-04-11
    • 2020-03-26
    • 2019-06-18
    • 2020-11-03
    • 1970-01-01
    相关资源
    最近更新 更多