сначала дрожать Где не отвечает (пожарный)

Несколько месяцев назад я выполнял функцию, при которой мое приложение ожидает пользовательских документов и отвечает соответствующим образом. Это работало как шарм, пока я не оптимизировал и не обновил проект до последней версии.

Если есть пользовательский документ, поток выдает документ и закрывает поток. Если в облачном хранилище нет данных пользователя, поток возвращает значение null и ожидает появления документа в облаке.

// 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;
  }
}

Если вы запустите этот код, не удаляя userDocumentStream.listen((event) {}), он будет работать без проблем, как и до обновления.

Мои вопросы: это ошибка? Почему это происходит? или я просто что то не так написал?

Изменить: я сделал собственный тест без firebase, и все работает нормально. Как раз в этом конкретном случае firstWhere() не слушает поток

Edit2: после еще нескольких тестов я обнаружил, что любой прослушиватель после userDocumentStream.first не будет работать. Теперь я еще больше сбит с толку, и мне действительно нужна помощь


person Infinity Atom    schedule 08.10.2020    source источник


Ответы (1)


Я думаю, что после вызова first() подписка отменяется, даже если в документации first указано иное:

Внутренне метод отменяет подписку после первого элемента. Это означает, что потоки с одной подпиской (не широковещательные) закрываются и не могут быть повторно использованы после вызова этого геттера.

Мое решение: создайте поток snapshots() для first() и один для 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;
}
person Infinity Atom    schedule 09.10.2020