Getting Null Value while Using Stream in Flutter - flutter

I was to trying to get an images from my firestore database. I used streambuilder to get images but it is showing me an error null value received. I checked the code completely and it was perfect. I dont know where the problem exist. Kindly help. Thanks.
Error
Null check operator used on a null value.
The following _CastError was thrown building StreamBuilder<QuerySnapshot<Map<String, dynamic>>>(dirty, state: _StreamBuilderBaseState<QuerySnapshot<Map<String, dynamic>>, AsyncSnapshot<QuerySnapshot<Map<String, dynamic>>>>#b7a15):
GetImage Code
class GetImage extends StatelessWidget {
const GetImage({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return StreamBuilder(
stream: FirebaseFirestore.instance
.collection('users')
.doc(FirebaseAuth.instance.currentUser!.uid)
.collection('cart')
.snapshots(),
builder: (context,
AsyncSnapshot<QuerySnapshot<Map<String, dynamic>>> snapshot) {
return ListView.builder(
itemCount: snapshot.data!.docs.length,
itemBuilder: (context, index) {
return Container(
child: Image.network(
snapshot.data!.docs[index].data()['imageUrl'],
fit: BoxFit.cover,
alignment: Alignment.center,
),
);
});
});
}
}

The error is showing because you have not provided the code for the loading state of a streambuilder, when the data is being loaded. Here is the updated code.
class GetImage extends StatelessWidget {
const GetImage({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return StreamBuilder(
stream: FirebaseFirestore.instance
.collection('users')
.doc(FirebaseAuth.instance.currentUser!.uid)
.collection('cart')
.snapshots(),
builder: (context,
AsyncSnapshot<QuerySnapshot<Map<String, dynamic>>> snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(
child: CircularProgressIndicator(), // or the data you want to show while loading...
);
}
return ListView.builder(
itemCount: snapshot.data!.docs.length,
itemBuilder: (context, index) {
return Container(
child: Image.network(
snapshot.data!.docs[index].data()['imageUrl'],
fit: BoxFit.cover,
alignment: Alignment.center,
),
);
});
});
}
}

You need to wait to fetch the data
class GetImage extends StatelessWidget {
const GetImage({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return StreamBuilder(
stream: FirebaseFirestore.instance
.collection('users')
.doc(FirebaseAuth.instance.currentUser!.uid)
.collection('cart')
.snapshots(),
builder: (context,
AsyncSnapshot<QuerySnapshot<Map<String, dynamic>>> snapshot) {
if (snapshot.hasData) {
return ListView.builder(
itemCount: snapshot.data!.docs.length,
itemBuilder: (context, index) {
return Container(
child: Image.network(
snapshot.data!.docs[index].data()['imageUrl'],
fit: BoxFit.cover,
alignment: Alignment.center,
),
);
});
}
if (snapshot.hasError) {
return Text("got error ${snapshot.error}");
}
return CircularProgressIndicator();
});
}
}

Related

displaying data from different firestore collections

I'm attempting display data from two diffrent collections within firestore , I treied to nest both streambuilds so i can particulary display the data as one stream , however I keep on getting the error bad state field doesnt exist with doc snapshot how can i fixing thus error , or is there another much more effective method i can use to display data from two diffrent collections in one class?
below is screenshot of the data(s) i want to display:
class OrderStream extends StatelessWidget {
static const String route = "/Order";
final CollectionReference meal =
FirebaseFirestore.instance.collection("menu");
final CollectionReference profile =
FirebaseFirestore.instance.collection("users");
OrderStream({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
body: StreamBuilder(
stream: profile.snapshots(),
builder: (context, AsyncSnapshot<QuerySnapshot> streamSnapshot) {
return StreamBuilder(
stream: meal.snapshots(),
builder:
(context, AsyncSnapshot<QuerySnapshot> streamSnapshot) {
if (!streamSnapshot.hasData) {
return const SizedBox(
height: 250,
child: Center(
child: CircularProgressIndicator(),
),
);
} else {
return ListView.builder(
itemCount: streamSnapshot.data!.docs.length,
itemBuilder: (context, index) {
final DocumentSnapshot documentSnapshot =
streamSnapshot.data!.docs[index];
return Column(
children: [
Text( documentSnapshot['price'],)
Text( documentSnapshot['name'],)
]
),
),
}
This is probably happening due to similar name for both snapshots.
The best way to check this is by renaming the snapshot for individual Streambuilder().
StreamBuilder(
stream: profile.snapshots(),
builder: (context, AsyncSnapshot<QuerySnapshot> profileStreamSnapshot) {
return StreamBuilder(
stream: meal.snapshots(),
builder:
(context, AsyncSnapshot<QuerySnapshot> mealStreamSnapshot) {
if (!streamSnapshot.hasData) {
//modified (renamed snapshot variable) code here
}
You can merge those two streams into 1 using library like rxdart which has combineLatest2 method although you can also use something like StreamZip to get the same effect.
I have used rxdart combineLatest2 as follows:
import 'package:rxdart/rxdart.dart';//import ⇐
class MyHomePage extends StatelessWidget {
final CollectionReference profile =
FirebaseFirestore.instance.collection("users");
final CollectionReference meal =
FirebaseFirestore.instance.collection("menu");
MyHomePage({super.key});
#override
Widget build(BuildContext context) {
return Scaffold(
body: StreamBuilder(
stream: Rx.combineLatest2(profile.snapshots(), meal.snapshots(),
(QuerySnapshot profileSnapshot, QuerySnapshot mealSnapshot) {
return [...profileSnapshot.docs, ...mealSnapshot.docs];
}),
builder: (context, AsyncSnapshot<List<DocumentSnapshot>> snapshot) {
if (!snapshot.hasData) {
return const SizedBox(
height: 250,
child: Center(
child: CircularProgressIndicator(),
),
);
} else {
return ListView.builder(
itemCount: snapshot.data!.length,
itemBuilder: (context, index) {
final DocumentSnapshot documentSnapshot =
snapshot.data![index];
final Map<String, dynamic> data =
documentSnapshot.data() as Map<String, dynamic>;
if (data.containsKey("price") && data.containsKey("name")) {
return Column(
children: [Text(data["price"]), Text(data["name"])],
);
} else {
return Container();
}
},
);
}
}),
);
}
}
You can also use Stream.merge() as follows:
final Stream<QuerySnapshot> mealsStream = meal.snapshots();
final Stream<QuerySnapshot> profilesStream = profile.snapshots();
//.. All that Scaffold stuff
stream: Stream.merge([mealsStream, profilesStream]),

displaying current logged user data

i need assistance on how i could possibly query a current logged in / signed in users data so i can display their specific data using the snippet of code below -
class AddStore extends StatelessWidget {
AddStore({Key? key}) : super(key: key);
final CollectionReference _user =
FirebaseFirestore.instance.collection("users");
#override
Widget build(BuildContext context) {
return Scaffold(
body: StreamBuilder(
stream: _user.snapshots(),
builder: (context, AsyncSnapshot<QuerySnapshot> streamSnapshot) {
if (!streamSnapshot.hasData) {
return const SizedBox(
height: 250,
child: Center(
child: CircularProgressIndicator(),
),
);
} else {
return ListView.builder(
itemCount: streamSnapshot.data!.docs.length,
itemBuilder: ((context, index) {
final DocumentSnapshot documentSnapshot =
streamSnapshot.data!.docs[index];
return Column(
children: [
Text(documentSnapshot['fullName']),
],
);
}));
}
}));
}
}
You need to add the current user id i.e FirebaseAuth.instance.currentUser!.uid while querying the data from users collection. And this results in single document so you should avoid using ListView
Change the StreamBuilder to this
StreamBuilder<DocumentSnapshot<Map<String, dynamic>>>(
stream: FirebaseFirestore.instance
.collection('users')
.doc(FirebaseAuth.instance.currentUser!.uid).snapshots(),
builder:
(BuildContext context, AsyncSnapshot<DocumentSnapshot> snapshot) {
if (snapshot.hasError) {
return const Text('Something went wrong');
}
if (snapshot.connectionState == ConnectionState.waiting) {
return const Text("Loading");
}
Map<String, dynamic> data =
snapshot.data!.data()! as Map<String, dynamic>;
return Text(data['fullName']);
},
)

The property can't be unconditionally accessed because the receiver can be 'null'...?

Hey guys i have an error and the code is bellow:
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';
class ChatScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: StreamBuilder(
stream: FirebaseFirestore.instance
.collection('chats/RMxQeDVKeYPOW940bWCH/messages/')
.snapshots(),
builder:(ctx, snapshot){
if (snapshot.connectionState == ConnectionState.waiting) {
return CircularProgressIndicator();
}
final docs = snapshot.data.docs;
return ListView.builder(
itemCount: docs.length,
itemBuilder: (ctx, index) => Container(
padding: EdgeInsets.all(8),
child: Text(docs[index]['text']),
),
);
},
),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: (){
FirebaseFirestore.instance
.collection('chats/RMxQeDVKeYPOW940bWCH/messages/')
.snapshots()
.listen((event) {
event.docs.forEach((element) {
print(element['text']);
});
});
},
),
);
}
}
Now the problem is in:
final docs = snapshot.data.docs;
And it says that:
The property 'docs' can't be unconditionally accessed because the receiver can be
'null'.
it is just having an error in docs after the snapshot data so can anybody please help me in that?
Thanks.
You need to make change is on this line
builder: (context, snapshot) to builder: (context, AsyncSnapshot snapshot)
then use
snapshot.data as snapshot.data!.
you are doing everything perfectly, except for the fact to add the Type for the StreamBuilder. Null safety alone won't solve your problem. Here is a piece of code that I altered a bit only in the body of Scaffold Widget.
StreamBuilder<QuerySnapshot>(
stream: FirebaseFirestore.instance
.collection('chats/RMxQeDVKeYPOW940bWCH/messages/')
.snapshots(),
builder:(ctx, snapshot){
if (snapshot.connectionState == ConnectionState.waiting) {
return CircularProgressIndicator();
}
if(snapshot.hasData) {
final docs = snapshot.data!.docs;
return ListView.builder(
itemCount: docs.length,
itemBuilder: (ctx, index) => Container(
padding: EdgeInsets.all(8),
child: Text(docs[index]['text']),
),
);
}
else {
return Text("Something Went wrong");
}
},
)
As the error message says, The property docs can't be unconditionally accessed because the receiver can be
null.
var docs = snapshot?.data?.docs;
return ListView.builder(
itemCount: docs?.length ?? 0,
itemBuilder: (ctx, index) => Container(
padding: EdgeInsets.all(8),
child: Text(docs?[index]['text'] ?? ''),
),
);
},
),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: (){
if(event.docs =! null)
FirebaseFirestore.instance
.collection('chats/RMxQeDVKeYPOW940bWCH/messages/')
.snapshots()
.listen((event) {
event.docs.forEach((element) {
print(element['text']);
});
});

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

Hey there I am new to flutter and i am currently working on firebase with flutter I am getting the following error , The argument type 'User?' can't be assigned to the parameter type 'Future<Object?>?' ,The error occurs in the futurebuilder in future argument ,
class messages extends StatelessWidget {
const messages({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return StreamBuilder(
builder: (ctx, AsyncSnapshot<QuerySnapshot> snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(
child: CircularProgressIndicator(),
);
}
final chatdoc = snapshot.data!.docs;
final userdata = FirebaseAuth.instance.currentUser;
return FutureBuilder(
future: userdata,
builder: (ctx, Snapshot) => ListView.builder(
reverse: true,
itemBuilder: (ctx, index) => messagebubble(
chatdoc[index]['Text'], chatdoc[index]['userId']),
itemCount: snapshot.data!.docs.length,
));
},
stream: FirebaseFirestore.instance
.collection('chats')
.orderBy('createdAt', descending: true)
.snapshots(),
);
}
}
The FirebaseAuth.instance.currentUser returns a User? not a Future. Thus, you can access it without the FutureBuilder, just return the messageBubble widget :
return messageBubble(
chatdoc[index]['Text'],
userData?.uid)

GridView with Flutter and Firestore

I`m trying to make a simple GridView from a cloud firestore record. I've followed a lot of video tutorials but without success. Here's the code:
import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
class EventList extends StatefulWidget {
#override
EventListState createState() => new EventListState();
}
class EventListState extends State<EventList> {
#override
Widget build(BuildContext context) {
return StreamBuilder(
stream: Firestore.instance.collection('events_flutter').snapshots(),
builder: (BuildContext context, DocumentSnapshot snapshot) {
if (!snapshot.hasData) {
return Center(child: const Text('Loading events...'));
}
return GridView.builder(
gridDelegate:
SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2),
itemBuilder: (BuildContext context, int index) {
return Text(snapshot['event_name']);
},
itemCount: snapshot.data.documents.length,
);
},
);}}
And this is the error message when hovering on "builder: (BuildContext context, DocumentSnapshot snapshot)".
Could anybody help me understand what is going on?
Thanks a lot.
You should replace the type of your snapshot from DocumentSnapshot to AsyncSnapshot.
...
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (!snapshot.hasData) {
return Center(child: const Text('Loading events...'));
}
...
And also, you might want to replace this line:
return Text(snapshot['event_name']);
to this:
return Text(snapshot.data.documents[index]['event_name']);
You collection().snapshot() returns QuerySnapshot, so you would have to change DocumentSnapshot to QuerySnapshot like this:
class EventListState extends State<EventList> {
#override
Widget build(BuildContext context) {
return StreamBuilder(
stream: Firestore.instance.collection('events_flutter').snapshots(),
builder: (BuildContext context, QuerySnapshot snapshot) {
if (!snapshot.hasData) {
return Center(child: const Text('Loading events...'));
}
return GridView.builder(
gridDelegate:
SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2),
itemBuilder: (BuildContext context, int index) {
return Text(snapshot['event_name']);
},
itemCount: snapshot.data.documents.length,
);
},
);}}