I am trying to asynchronously pull data from firestore in a streambuilder (all within a list view). The problem with the approach I have now is that nothing displays on the screen. I tried setting state (after i check if the screen is mounted, but to no avail). I know the correct data is being pulled because it prints to the screen, but for some reason, it just does not display on the screen.
here's a sample of my list view below:
Widget _showFriends() {
return Expanded(
child: StreamBuilder<List<Future<AppUser>>>(
stream: db.friendStream(),
builder: (context, snapshot) {
if(snapshot.hasData) {
print("in here");
final friends = snapshot.data!;
var friend;
String username = "";
String firstName = "";
String photoUrl = "";
return ListView.builder(
keyboardDismissBehavior: ScrollViewKeyboardDismissBehavior.onDrag,
itemCount: snapshot.data!.length,
itemBuilder: (context, index) {
friends[index].then((value) {
friend = value;
username = value.username;
firstName = value.firstName;
//photoUrl = value.photoUrl;
print("friend username -- " username);
});
return GestureDetector(
onTap: () {
Navigator.of(context).push(MaterialPageRoute(builder: (context)
=> IndividualProfile(
sourceType: SourceType.friends,
name: friend.firstName,
userName: friend.username,
aboutMe: friend.aboutMe,
photoUrl: friend.photoUrl,
individualUid: friend.uid,
)
));
},
child: ListTile(
title: Text(username),
subtitle: Text(firstName),
/*leading: CircleAvatar(
backgroundImage: CachedNetworkImageProvider(photoUrl),
),*/
),
);
},
);
}
else if(snapshot.hasError) {
print(snapshot.error.toString());
return const Center(
child: Text("An error occurred please try again later"),
);
}
else {
return const Center(
child: CircularProgressIndicator(),
);
}
}
)
);
}
Pleas let me know any suggestions. I thoroughly appreciate it!
CodePudding user response:
The problem is that friends[index]
is a future
. You did not await
it before returning GestureDetector
.
return GestureDetector(...)
would be called before friends[index].then
callback. Variable friend
would still be null when return GestureDetector(...)
is called.
The correct way to wait
for it would be with a FutureBuilder
.
Try this:
Widget _showFriends() {
return Expanded(
child: StreamBuilder<List<Future<AppUser>>>(
stream: db.friendStream(),
builder: (context, snapshot) {
if (snapshot.hasData) {
final friends = snapshot.data!;
return ListView.builder(
keyboardDismissBehavior: ScrollViewKeyboardDismissBehavior.onDrag,
itemCount: snapshot.data!.length,
itemBuilder: (context, index) {
// here I am awaiting friends[index]'s future
return FutureBuilder<AppUser>(
future: friends[index],
builder:
(BuildContext context, AsyncSnapshot<AppUser> snapshot) {
if (snapshot.hasError) {
return const Center(
child: Text(
'An error occurred. Please try again later',
),
);
}
if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(child: CircularProgressIndicator());
}
final friend = snapshot.data!;
return GestureDetector(
onTap: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => IndividualProfile(
sourceType: SourceType.friends,
name: friend.firstName,
userName: friend.username,
aboutMe: friend.aboutMe,
photoUrl: friend.photoUrl,
individualUid: friend.uid,
),
),
);
},
child: ListTile(
title: Text(friend.username),
subtitle: Text(friend.firstName),
// leading: CircleAvatar(
// backgroundImage:
// CachedNetworkImageProvider(friend.photoUrl),
// ),
),
);
},
);
},
);
}
if (snapshot.hasError) {
print(snapshot.error.toString());
return const Center(
child: Text('An error occurred please try again later'),
);
}
return const Center(child: CircularProgressIndicator());
},
),
);
}