Firebase RealTime database Flutter stream never returns problem

Viewed 469

I am trying to read a list of objects from Realtime database in Firebase with no success so far.

I am following the official tutorial from Firecasts on the following link: https://www.youtube.com/watch?v=sXBJZD0fBa4

Here is how the database looks like: enter image description here

Here is the code I have written:

The following is the class I have created for the objects I will be reading from database:

class TestData {
  final String name;
  final String surname;
  final String age;

  TestData({
    required this.name,
    required this.surname,
    required this.age,
  });

  factory TestData.fromRTDB(Map<dynamic, dynamic> data) {
    return TestData(
      name: data["Name"],
      surname: data["Surname"],
      age: data["Age"],
    );
  }
}

Here is how I try to read it from the database:

class TestDataGetter {
  final _db = FirebaseDatabase.instance.ref();

  Stream<List<TestData>> getTestDataStream() {
    final csPostprocessedStream = _db.child("test_data/").onValue;
    var streamToPublish = csPostprocessedStream.map((event) {
      final testDataMap = Map<dynamic, dynamic>.from(
          event.snapshot.value as Map<dynamic, dynamic>);

      final testDataList = testDataMap.entries.map((element) {
        return TestData.fromRTDB(Map<dynamic, dynamic>.from(element.value));
      }).toList();
      return testDataList;
    });
    return streamToPublish;
  }
}

And here is the screen where I would like to show the data:

class TestDataScreen extends StatelessWidget {
  const TestDataScreen({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Column(
        children: [
          StreamBuilder(
              stream: TestDataGetter().getTestDataStream(),
              builder: (context, snapshot) {
                if (!snapshot.hasData) {
                  print("Waiting");
                  return const CircularProgressIndicator(color: Colors.white);
                } else if (snapshot.hasError) {
                  print("Error occured...");
                  return const CircularProgressIndicator(color: Colors.white);
                } else {
                  final testDataList = snapshot.data as List<TestData>;
                  return Text(
                      testDataList[0].name + " / " + testDataList[1].name,
                      style: Theme.of(context).textTheme.headline3,
                      textAlign: TextAlign.center);
                }
              }),
        ],
      ),
    );
  }
}

But I can never see the data on the screen. The spinning wheel is the only thing I see and on the console I see the print out as "Waiting" (as I print out this text in the code above).

It gets stuck in if (!snapshot.hasData).

I am clueless after spending hours on this.

2 Answers

Try the following

!snapshot.hasData || snapshot.data.documents.isEmpty

The problem here is that snapshots() will also return a QuerySnapshot when the query returns no documents. Thus, you could expand your condition like this:

Here is what I have should help you

if (snapshot.hasError) {
            //TODO: we need to make sure we caputer this error message snapshot.error
            return const PlaceHolder(
              url: 'assets/animations/404-error.json',
              message: ErrorMessages.getDogsError,
            );
          } else if (snapshot.data == null || snapshot.data!.isEmpty) {
            return const PlaceHolder(
              url: 'assets/animations/no-dog-animation.json',
              message: AppMessages.noDogMessage,
            );
          } else if (!snapshot.hasData) {
}

Your problem is that you most likely have an error.
The issue is, your error handling is actually never reached, because in case of an error, !hasData will still be true

You may want to execute the hasError condition before !hasData:

if (snapshot.hasError) {
  return Text('error');
} else if (!snapshot.hasData) {
  return Text('loading');
} else {
  return Text('data');
}
Related