I am experiencing weird(to my knowledge) behaviour of StreamListener data when I turn on two emulators.
I have a block of code to read Firebase's RealtimeDB and return it in ListView.
body: StreamBuilder(
stream: _database.onValue,
builder: (context, snapshot) {
List<FirstRoundQuestion> frqList = [];
if (snapshot.hasData) {
final firstRoundQuestion = Map<dynamic, dynamic>.from(
(snapshot.data! as DatabaseEvent).snapshot.value
as Map<dynamic, dynamic>);
firstRoundQuestion.forEach((key, value) {
final frq = Map<String, dynamic>.from(value);
frqList.add(FirstRoundQuestion(
question: frq['question'],
answer: frq['answer'],
answered: frq['answered']));
});
return ListView.builder(
reverse: true,
physics: NeverScrollableScrollPhysics(),
controller: _controller.pageController,
itemCount: frqList.length,
itemBuilder: (context, index) {
return Row(
children: [
Text('${frqList[index].question}'),
TextButton(
onPressed: () {}
child: Text('${frqList[index].answered}'))
],
);
},
);
} else {
return Text("Doesn't work");
}
}));
What I get when buiild app on mobile simulator and then edge simulator is two different orders of this list, first one is ascending and the other one is descending. What am I missing here guys? :o
Hopefully I explained understandably.
CodePudding user response:
To show the items in a specific order, you need to do two things:
- Retrieve the items in that order from the database.
- Then process them in the order you received them in your code.
If you're not requesting the items in a specific order from the database yet, you can for example do:
body: StreamBuilder(
stream: _database.orderByKey().onValue,
...
Once you requests the item in a certain order, it's this code in your builder that fails to process the items in order:
if (snapshot.hasData) {
final firstRoundQuestion = Map<dynamic, dynamic>.from(
(snapshot.data! as DatabaseEvent).snapshot.value
as Map<dynamic, dynamic>);
firstRoundQuestion.forEach((key, value) {
final frq = Map<String, dynamic>.from(value);
frqList.add(FirstRoundQuestion(
question: frq['question'],
answer: frq['answer'],
answered: frq['answered']));
});
The order of the items in a map is undefined, so when you convert the entire value of the snapshot to a map, you are losing the order of the items.
The solution to processing the items in order is to loop over the children
property of the snapshot:
(snapshot.data! as DatabaseEvent).snapshot.children.forEach((snapshot) {
final frq = Map<Sting, dynamic>.from(snapshot.value as Map<dynamic, dynamic>);
frqList.add(FirstRoundQuestion(
question: frq['question'],
answer: frq['answer'],
answered: frq['answered']));
})