0

I'm using firebase and I have this:

Stream<QuerySnapshot> qs = FirebaseFirestore.instance
        .collection("$mypath")
        .orderBy(order)
        .limit(10)
        .startAfterDocument(lastDoc)
        .snapshots();

When I pass qs to a StreamBuilder, the returned snapshot can do snapshot.hasError.

      StreamBuilder(
        stream: qs, 
        builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
          if (snapshot.hasError) ... // hasError works
        },
      )

However when I listen to the stream, things like hasError, hasData ..., are not recognized anymore

    qs.listen((event) {
      if (event.hasError) // error: The getter 'hasError' isn't defined for the type 'QuerySnapshot<Object?>'.
    });

I still can do event.docs and I get the data successfully, but I can't listen for errors. Am I doing something wrong?

SIMMORSAL
  • 1,402
  • 1
  • 16
  • 32

1 Answers1

1

The hasError and hasData are properties defined on the AsyncSnapshot object, and only exist when you're inside the StreamBuilder, where it essentially wraps the state of the asynchronous operation. When you call AsyncSnapshot.data in your code, you get back the QuerySnapshot that encapsulates the data from Firebase.

When you listen to the stream yourself, there is no AsyncSnapshot and you start with a QuerySnapshot, which is a Firestore object defined here. As you can see, that doesn't have hasError or hasData as those are exposed different.

This is definitely initially confusing as there are quite a few types of snapshots involved here, so I recommend checking out What is the difference between existing types of snapshots in Firebase?

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
  • Been using firebase for a year now and it's still definitely confusing! ... What I'm trying to do is get the data from a Repository class which only Bloc has access to, and feed the data to widgets as they are available. It's doable with `QuerySnapshot`, but I see no way to handle the errors now. Is it possible to do this, or should I get the data from widgets, and sync them with the Bloc? – SIMMORSAL Jun 11 '21 at 20:18
  • Handling errors just works differently when you listen to the stream yourself. You can check for errors with `handleError` as far as I can tell: https://api.dart.dev/stable/2.13.1/dart-async/Stream/handleError.html – Frank van Puffelen Jun 11 '21 at 21:57
  • I added this `...snapshots().handleError( (e) => print("11111 $e")` but the function never executes. I guess firebase handles the errors internally (that's how there's `hasError` in AsyncSnapshot) and won't rethrow it for the `handleError` to listen to it. – SIMMORSAL Jun 11 '21 at 22:27
  • I'm not too familiar with this part, but this is how it is implemented (for Android, but all platforms work pretty much the same): https://github.com/FirebaseExtended/flutterfire/blob/64ee628516af5399afd4e02bfb86862bc6452d6c/packages/cloud_firestore/cloud_firestore/android/src/main/java/io/flutter/plugins/firebase/firestore/streamhandler/QuerySnapshotsStreamHandler.java#L36-L48 and then on the Flutter side: https://github.com/FirebaseExtended/flutterfire/blob/master/packages/cloud_firestore/cloud_firestore_platform_interface/lib/src/method_channel/method_channel_query.dart#L129-L162 – Frank van Puffelen Jun 11 '21 at 22:59