Listview.builder inside StreamBuilder is rebuilding/flickering - flutter

So I used Streambuilder to fetch CartItems from Firestore and it starting to flicker and it always goes to the top. Also can't scroll down, it always goes to the top, I used streambuilder in different parts of the app and it works perfectly but here it causing the problem...
Stream<QuerySnapshot<Map<String, dynamic>>> getCartStream() {
CollectionReference<Map<String, dynamic>> ref = FirebaseFirestore.instance
.collection("users")
.doc(FirebaseAuth.instance.currentUser!.uid)
.collection("cart");
Stream<QuerySnapshot<Map<String, dynamic>>> stream = ref.snapshots();
return stream;
}
StreamBuilder(
stream: getCarStream(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return Container();
} else {
return ListView.builder(
itemCount: snapshot.data!.docs.length,
itemBuilder: (context, index) {
ProductModel productModel = ProductModel.fromMap(snapshot.data!.docs[index].data());
return CartItem(product: productModel);
},
);
}
},
)),
Rest of the code
Gif of the Problem

just remove the initState(), will work fine. if not then kindly share CARTITEM(..) class.

Related

my Querysnapshot Map String become AsyncSnapshot<Object> with no reason

I have a streamBuilder where the "snapshots()" change from Stream<QuerySnapshot<Map<String, dynamic>>> to AsyncSnapshot<Object?>.
This is weird because I have another app, with identical code and works fine.
The problem is, I cannot access "snapshot.data.docs" and all firestore datas.
Why is happening?
my code:
body: StreamBuilder(
//Stream<QuerySnapshot<Map<String, dynamic>>>
stream: firestore.collection('Books').orderBy('name').snapshots(),
//AsyncSnapshot<Object?>
builder: (context, snapshot ) {
if (snapshot.connectionState == ConnectionState.waiting)
return Center(child: CircularProgressIndicator());
{
final document = snapshot.data?; //error here
return ListView.builder(
itemCount: document?.length,
itemBuilder: (context, index) {
return Column(
Declare your StreamBuilder Widget response type as a dynamic, and you should use
snapshot.data.docs without any problem.
body: StreamBuilder<dynamic>(
stream: FirebaseFirestore.instance.collection('Books').orderBy('name').snapshots(),
builder: (context, snapshots) {
if(snapshots.hasData){
print(snapshots.data.docs.toString());
}});

How to observe Firebase changes in Flutter using StreamBuilder

I am trying to observe Firebase collection changes. In the first run, Listview is not building. After changing data on Firebase, then listview is rendered properly but previous snapshot is used because I see my old data on the screen.
Any idea to find the error?
#override
Widget build(BuildContext context) {
return BlocListener<VoteCubit, VoteState>(
listener: (context, state) {
if (state.status == FormStatus.success) {
print("Success");
} else if (state.status == FormStatus.inprogress) {
print("In progress");
} else if (state.status == FormStatus.fail) {
print("fail");
} else {
print("Empty Area");
}
},
child: StreamBuilder<QuerySnapshot>(
stream: FirebaseFirestore.instance.collection('liveSurvey').snapshots(),
builder: (context, snapshot) {
final voteCubit = context.read<VoteCubit>();
final voteState = voteCubit.state;
if (snapshot.hasData) {
voteCubit.getAllRooms(snapshot);
print("Here");
return ListView.builder(
itemCount: voteState.rooms.length,
itemBuilder: (context, i) {
print("Inside Listview");
. . .
Use stream builder like this for real time data.
child: StreamBuilder<QuerySnapshot>(
stream: FirebaseFirestore.instance
.collection("travellers/India/details")
.where(
'firestore_id',
isEqualTo: widget.get_firestore_id,
)
.snapshots(),
builder:
(BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
print('play lodader')
}else if (snapshot.hasData) {
print('your_ui_here')
}

Modify Future Builder inside Stream Builder to avoid widget flickering

I am using a FutureBuilder inside a StreamBuilder that updates the UI every time a document is added to the activity collection, to get some aditional data from Firestore. The problem is that the FutureBuilder returns a SizedBox widget while the ConnectionState is waiting causing the all the cards to dissapear for a second. I would like to avoid this flickering since it causes a bad ui experience for users.
Is there a way to query the required user data in the activity stream so it all returns at once that way I can remove the FutureBuilder?
If not ... what would be a solution for this?
activityStream() {
return FirebaseFirestore.instance
.collection('activity')
.orderBy('timestamp', descending: true)
.limit(55)
.snapshots();
}
if (snapshot.connectionState == ConnectionState.waiting) {
return const SizedBox(
height: 65.0,
);
}
StreamBuilder<QuerySnapshot>(
stream: activityStream(),
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (snapshot.hasError) {
return Text('Error: ${snapshot.error}');
}
switch (snapshot.connectionState) {
case ConnectionState.waiting:
return const Center(child: CircularProgressIndicator());
default:
final activityContent = snapshot.data?.docs
.map((data) => ActivityModel.fromFirestore(data))
.toList();
return Scrollbar(
controller: widget.scrollController,
child: ListView.builder(
shrinkWrap: true,
controller: widget.scrollController,
itemCount: activityContent!.length,
itemBuilder: (context, i) {
return FutureBuilder(
future: FirebaseFirestore.instance
.collection('users')
.where('uid', whereIn: activityContent[i].players)
.get(),
builder: (BuildContext context,
AsyncSnapshot<QuerySnapshot> snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const SizedBox(
height: 65.0,
);
}
final users = snapshot.data!.docs.map((e) {
return UserModel.fromFirestore(e);
}).toList();
return MyWidget(
users: users,
);
},
);
},
),
);
}
},
);

The argument type 'Future<Stream<QuerySnapshot<Object?>>>' can't be assigned to the parameter type 'Stream<QuerySnapshot<Object?>>?'

I have a function which fetch a stream and do querysnapshot in cloud firestore to fetch some data and then return it.
Future<Stream<QuerySnapshot>> getSearchedUser() async {
final Stream<QuerySnapshot> users = FirebaseFirestore.instance
.collection("users")
.where("email", isEqualTo: searchUserTextController.text)
.snapshots();
return users;
}
and I am trying to function as stream in my stream builder but I am getting an error
StreamBuilder<QuerySnapshot>(
stream: getSearchedUser(),
builder: (BuildContext context,
AsyncSnapshot<QuerySnapshot> snapshot) {
if (snapshot.hasError) {
return const Text("Error Occured");
}
if (snapshot.connectionState == ConnectionState.waiting) {
return const Text("Loading Data");
}
final data = snapshot.requireData;
return ListView.builder(
scrollDirection: Axis.vertical,
shrinkWrap: true,
itemCount: data.size,
itemBuilder: (context, index) {
return Text("${data.docs[index]["email"]}");
});
},
),
Error is: -
The argument type 'Future<Stream<QuerySnapshot<Object?>>>' can't be assigned to the parameter type 'Stream<QuerySnapshot<Object?>>?'.
Actually, you don't need 'Future' keyword because Stream already async structure.
So, you can ty below code;
Stream<QuerySnapshot> getSearchedUser() async {
return FirebaseFirestore.instance
.collection("users")
.where("email", isEqualTo: searchUserTextController.text)
.snapshots();
}

FutureBuilder doesn't work properly with Firestore

can't create a query using FutureBuilder.
Firestore is at the latest version.
This is the case for both Android and iOS devices, any ideas?
return FutureBuilder<QuerySnapshot>(
future: Firestore.instance
.collection('productlist')
.where('productid', isEqualTo: pid)
.limit(
1), // a previously-obtained Future<String> or null
builder: (BuildContext context,
AsyncSnapshot<QuerySnapshot> snapshot) {
if (snapshot.hasData) {
productname = snapshot.data.documents[0]['productname'];
print("productname:" + productname);
}
else{
productname = "0";
}
},
);
I think the issue here is that you are not returning a widget.
Try the code below
FutureBuilder(
future: Firestore.instance
.collection('productlist')
.where('productid', isEqualTo: pid)
.limit(1),
builder: (ctx, snapshot) {
if (snapshot.connectionState == ConnectionState.done && snapshot.hasData) {
return Text(snapshot.data.documents[0]['productname']);
} else {
return Text("0");
}
},
),
u can use stream builder instead it works pretty well :
return StreamBuilder<QuerySnapshot>(
stream: Firestore.instance.collection('productlist').where('productid', isEqualTo: pid).limit(1),
builder: (context, snapshot) {
if (snapshot.data != null) {
// Here u will get list of document snapshots
final List<DocumentSnapshot> documents = snapshot.data.documents;
// now u can access each document by simply specifying its number
// u can also use list view to display every one of them
return ListView.builder(
itemCount: documents.length,
itemBuilder: (context, int index) => Text(documents[index]['productname']),
);
} else {
// Show loading indicator here
}
},
);