当侦听Firestore快照时,StreamBuilder挂起

时间:2018-10-22 18:18:45

标签: firebase flutter google-cloud-firestore subscription

复制步骤

由于没有好的教程使用firebasebloc pattern,因此我尝试在Firebase中使用bloc模式,并且遇到了麻烦。

在执行此操作时,我遇到了奇怪的事情,并努力找出问题所在,但未能成功。

我已经创建了UserBloc,并在听完UserModel之后尝试设置Firestore snapshot

class UserBloc extends Object {
    final _user = StreamController<UserModel>.broadcast();
    final _uid = StreamController<String>.broadcast();

    Stream<UserModel> get user => _user.stream;
    Stream<String> get uid => _uid.stream;

    Function(UserModel) get setUser => _user.sink.add;
    Function(String) get setUID => _uid.sink.add;

    Stream<DocumentSnapshot> userStream;

    UserBloc() {
        uid.listen((uid) {
            print('user : $uid');
            if (uid != null) {
                fromUID(uid);
            }
        });
    }

    fromUID(String uid) {
        print('fromUID');
        userStream = Firestore.instance.collection('users').document(uid).snapshots();

        /// works ok when I delete below subscription
        userStream.listen((data) {
        });
    }

    dispose() {
        _user.close();
        _uid.close();
    }
}

然后,我在小部件内使用了StreamBuilder,如下所示。

StreamBuilder(
    stream: userBloc.userStream,
    builder: (context, snapshot) {
        print(snapshot.connectionState);
        print(snapshot.data);
        return Text('testing');
    },
);

问题是 snapshot.connectionState**始终是** waiting 。但是,当我删除订阅代码userStream.listen((data) {时,我可以使它工作。所有示例都进行侦听并在bloc的构造函数中设置数据。我不知道为什么会这样。

2 个答案:

答案 0 :(得分:0)

我认为您在使用Streambuilder时必须删除Bloc中流控制器的侦听语句。由于Streambuilder是Bloc中的侦听流控制器,因此Streambuilder和Bloc中的侦听语句之间存在重复问题。

答案 1 :(得分:0)

问题是.snapshot()返回BroadcastStream。

https://www.dartlang.org/articles/libraries/broadcast-streams

第一次订阅(构造函数中的.listen)之后,该流处于活动状态,并且在数据可用/更改时调用了onData回调。

当UI订阅流时,该流已经处于活动状态(读取操作已完成),因此 ConnectionState将始终返回等待状态,直到下一次文档更新为止。

尝试像这样修改您的代码,以重现:

/// works ok when I delete below subscription
userStream.listen((data) => print(data));

Future.delayed(Duration(seconds: 5),
        () => userStream.listen((onData) => print(onData))
);

第二个回调将触发。

为避免这种情况,您必须进行一些缓存。

将rxdart添加到您的依赖项中 https://pub.dev/packages/rxdart

像这样修改代码

userStream = Observable(Firestore.instance.collection('users').document(uid).snapshots())
.shareReplay(maxSize: 1);
  

它将重播发出的值给任何新的侦听器,直到给定   [maxSize]。