Get data from async function inside ListView (without FutureBuilder)

Issue

My app’s home page uses a ListView.builder to create a feed of posts. Each post has to show the owner’s profile picture as well as other data. In the ListView.builder I call a function to get the profile picture URL from Firebase
like this:

ListView.builder(
          itemCount: listPosts.length,
          itemBuilder: (BuildContext context, int index) {
            // We retrieve the post at index « index »
            final post = listPosts[index];
            // Get name from id
            var parts = post.id.split('_');
            var username = parts[0].trim();
            // Get pfpUrl
            String pfpUrlString = pfpUrl(username);
            return _buildPost(
                username, post.postUrlString, post.caption, pfpUrlString);
          }),

The “`pfpUrl(username)”’ function that I call looks like this and returns the URL as a string:

  pfpUrl(String username) async {
    // Get pfpUrl
    String pfpUrlString = await FirebaseStorage.instance
        .ref()
        .child("$username/profile_picture.png")
        .getDownloadURL();
    return pfpUrlString;
  }

So the function returns the String but I can’t call it using await inside the ListView.builder because it’s not an async function. I can’t use a FutureBuilder because the username comes from the post id which I can only get inside the ListView.Builder. Instead of returning a value, I tried making a global variable and setting it to each URL in the function, then setting that variable as the URL in the builder. That doesn’t work because it ends up putting random profile pictures on each post. Can someone please give me solution ideas?

Solution

You can use this widget to load and display profile photo from username.
Use like this in your _buildPost method.:

ProfileImageWidget('username')
class ProfileImageWidget extends StatelessWidget {
  final username;
  
  ProfileImageWidget(this.username){
    
    getUrl = FirebaseStorage.instance
        .ref()
        .child("$username/profile_picture.png")
        .getDownloadURL();
    
  }
  
  late Future<String> getUrl;
  
  @override
  Widget build(BuildContext context) {
    return FutureBuilder<String>(
        future: getUrl, 
        builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
          if(!snapshot.hasData) return Text('getting profile url');
          return Image.network(snapshot.data!);
        });
       
  }
}

Answered By – Mehmet Demir

Answer Checked By – Katrina (FlutterFixes Volunteer)

Leave a Reply

Your email address will not be published.