flutter firstWhere not responding (firestore)

589 Views Asked by At

I did a function a few months ago where my application is waiting for the user documents and responding accordingly. It was working like a charm until I optimized and updated the project to the last version.

If there is a user document, the stream yields the document and closes the stream. If there is no user data in the cloud firestore, the stream yields null and awaits for the document to appear in the cloud.

// this function doesn't work properly and it should work but `firstWhere` is not
// listening to the stream unless there is a listener already which makes no sense

static Stream<DocumentSnapshot> get getUserDocumentWhenExists async* {
  User user = FirebaseAuth.instance.currentUser;
  if (user == null) throw 'No user is signed in';

  FirebaseFirestore firebase = FirebaseFirestore.instance;
  CollectionReference usersCollection = firebase.collection('users');
  Stream<DocumentSnapshot> userDocumentStream = usersCollection.doc(user.uid).snapshots();

  userDocumentStream.listen((event) {}); // <= this is here for the code to work

  DocumentSnapshot userDocument = await userDocumentStream.first;
  if (userDocument.exists == false) {
    yield null;
    yield await userDocumentStream.firstWhere((userDocument) {
      // not beeing called without a previous listener
      return userDocument.exists;
    });
  } else {
    yield userDocument;
  }
}

If you run this code without removing userDocumentStream.listen((event) {}) it will work without a problem as it did before the update.

My questions are: Is this a bug? Why is this happening? or did I just wrote something wrong?

Edit: I made a custom test without firebase and everything works fine. Just in this particular case firstWhere() is not listening to the stream

Edit2: after some more testing I discovered that any listener after userDocumentStream.first will not work. Now I'm more confused and I really need some help

1

There are 1 best solutions below

0
On

I think after first() is called, the subscription is canceled even if in the first documentation it says otherwise:

"Internally the method cancels its subscription after the first element. This means that single-subscription (non-broadcast) streams are closed and cannot be reused after a call to this getter."

My solution: Create a snapshots() stream for the first() and one for firstWhere()

final documentReference = usersCollection.doc(user.uid);

final userDocument = await documentReference.snapshots().first;
if (userDocument.exists == false) {
  yield null;
  yield await documentReference.snapshots().firstWhere((userDocument) {
    return userDocument.exists;
  });
} else {
  yield userDocument;
}