Home > Enterprise >  ListView.builder only loads after hot-reloading flutter app
ListView.builder only loads after hot-reloading flutter app

Time:12-30

When a user logs into my flutter app, they have to log in, then they are brought to a screen with a feed of posts. I use a ListView.builder to take a list of posts from my database and create the feed of posts. My issue is that when the feed screen is initially launched, the ListView doesn't load. As soon as I hot-reload the app the list does load. I imagine there's a very obvious minor mistake in my code but I just can't find it. I will put all of the code from the feed screen below, please take a look and let me know if you see the mistake.

class HomeScreen extends StatefulWidget {
  const HomeScreen({Key? key}) : super(key: key);

  static const String id = "home_screen";

  @override
  _HomeScreenState createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
  // List allposts = [(post: Post, owner: String)];

  Color _likeButtonColor = Colors.black;

  Widget _buildPost(String username, String imageUrl, String caption) {
    return Container(
      color: Colors.white,
      child: Column(
        children: [
          Container(
            height: 50,
            color: Colors.deepOrangeAccent[100],
            child: Row(
              children: [
                SizedBox(width: 5),
                CircleAvatar(),
                SizedBox(width: 5),
                Text(username, style: TextStyle(fontSize: 15)),
                SizedBox(width: 225),
                Icon(Icons.more_horiz)
              ],
            ),
          ),
          Stack(
            children: [
              Image.asset("images/post_background.jpg"),
              Padding(
                padding: const EdgeInsets.all(20.0),
                child: ClipRRect(
                    borderRadius: BorderRadius.circular(8.0),
                    child: Image.network(imageUrl, fit: BoxFit.cover)),
              ),
            ],
          ),
          Container(
            height: 100,
            child: Column(
              children: [
                const SizedBox(height: 5),
                Row(
                  mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                  children: [
                    IconButton(
                        onPressed: () {
                          setState(() {
                            HapticFeedback.lightImpact();
                          });
                        },
                        icon: Icon(Icons.thumb_up_alt_outlined, size: 30)),
                    Text("l", style: TextStyle(fontSize: 30)),
                    Icon(Icons.ios_share, size: 30)
                  ],
                ),
                Row(
                  mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                  children: [
                    Text(caption, style: const TextStyle(fontSize: 15))
                  ],
                )
              ],
            ),
          )
        ],
      ),
    );
  }

  List<Post> listPosts = [];

  fetchPosts() async {
    final userRef = FirebaseFirestore.instance.collection('users');

    final QuerySnapshot result = await userRef.get();

    result.docs.forEach((res) async {
      print(res.id);
      QuerySnapshot posts = await userRef.doc(res.id).collection("posts").get();

      posts.docs.forEach((res) {
        listPosts.add(Post.fromJson(res.data() as Map<String, dynamic>));
      });
    });
  }

  @override
  void initState() {
    fetchPosts();
    print(listPosts);
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: ListView.builder(
          itemCount: listPosts.length,
          itemBuilder: (BuildContext context, int index) {
            // We retrieve the post at index « index »
            final post = listPosts[index];
            // Replace with your actual implementation of _buildPost
            return _buildPost(post.id, post.postUrlString, post.caption);
          }),
    );
  }
}

CodePudding user response:

The reason is that you need to rebuild your screen to show the reflected changes after performing an async operation (use setState to rebuild the UI). And secondly .forEach loop is not built to carry async stuff and are less efficient then a normal for loop so its better to change it.

fetchPosts() async {
    final userRef = FirebaseFirestore.instance.collection('users');

    final QuerySnapshot result = await userRef.get();

    for(var res in result.docs)async{
      print(res.id);
      QuerySnapshot posts = await userRef.doc(res.id).collection("posts").get();

      posts.docs.forEach((res) {
        listPosts.add(Post.fromJson(res.data() as Map<String, dynamic>));
      });
    }

    setState((){});//call it after end of your function
  }

Ps:- You can use a variable named loading to show progress indicator and set it to false after fetching data in setState.

  • Related