I have two StreamBuilders and want to use one StreamBuilder's outputs for another StreamBuilder. For that, I made a nested StreamBuilder but it doesn't work. The child StreamBuilder seems not to take the parent StreamBulder's output well. In my code, userModelSnapshot always has no data. I checked functions inside both stream sources work.
I got some error code " _CastError (type 'Null' is not a subtype of type 'Map<dynamic, dynamic>' in type cast)" and "UserService.getUserInfo anonymous closure"
Any help would be appreciated.
Here is my code
class ListPostsPage extends StatefulWidget {
const ListPostsPage({Key? key}) : super(key: key);
@override
State<ListPostsPage> createState() => _ListPostsPageState();
}
class _ListPostsPageState extends State<ListPostsPage> {
PostService postService = PostService();
UserService userService = UserService();
@override
Widget build(BuildContext context) {
String location = context.read<LocationModel?>()?.city! ?? '';
return StreamBuilder(
stream: postService.getPosts(location),
builder:
(BuildContext context, AsyncSnapshot<List<PostModel?>?> snapshot) {
if (!snapshot.hasData) {
return const Center(child: CircularProgressIndicator());
}
return ListView.builder(
itemCount: snapshot.data!.length,
itemBuilder: (context, index) {
final post = snapshot.data![index];
return StreamBuilder(
stream: userService.getUserInfo(post?.creator ?? ''),
builder: (BuildContext context,
AsyncSnapshot<UserModel?> userModelSnapshot) {
if (!userModelSnapshot.hasData) {
return const Center(child: CircularProgressIndicator());
}
inspect(userModelSnapshot);
return Card(
color: Colors.grey[300],
child: ListTile
title: Padding(
padding: EdgeInsets.fromLTRB(0, 15, 0, 15),
child: Row(
children: [
Text(
userModelSnapshot.data?.toString() ?? 'NO'),
userModelSnapshot.data?.profileImageUrl != null
? CircleAvatar(
radius: 20,
backgroundImage: NetworkImage(
userModelSnapshot
.data!.profileImageUrl!))
: const Icon(
Icons.person,
size: 40,
),
SizedBox(width: 10),
userModelSnapshot.data?.name != null
? Text(userModelSnapshot.data!.name!)
: const Text('No name')
],
),
),
subtitle: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: EdgeInsets.fromLTRB(0, 15, 0, 15),
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Text(
post?.text ?? "",
style: TextStyle(color: Colors.black),
),
SizedBox(height: 20),
//Text(post.creator),
Text((post?.timestamp.toDate() ?? 0)
.toString()),
]),
),
],
),
),
);
});
});
});
}
}
Stream<List<PostModel>?> getPosts(location) {
return FirebaseFirestore.instance
.collection("posts")
.where("location.city", isEqualTo: location)
.snapshots()
.map((snapshot) {
return snapshot.docs.map((doc) {
return PostModel(
id: doc.id,
creator: (doc.data())["creator"] ?? "",
text: (doc.data())["text"] ?? "",
timestamp: (doc.data())["timestamp"] ?? 0,
location: (doc.data())["location"] ?? {},
);
}).toList();
}
Stream<UserModel?> getUserInfo(uid) {
return FirebaseFirestore.instance
.collection('users')
.doc(uid)
.snapshots()
.map((snapshot) {
return UserModel(
id: snapshot.id,
name: (snapshot.data() as Map)['name'] ?? '',
email: (snapshot.data() as Map)['email'] ?? '',
profileImageUrl: (snapshot.data() as Map)['profileImageUrl'] ?? '',
timestamp: (snapshot.data() as Map)['timestamp'] ?? 0);
});
}