ListView.builder 仅在热重载 flutter 应用程序后加载

ListView.builder only loads after hot-reloading flutter app

当用户登录到我的 flutter 应用程序时,他们必须登录,然后他们会被带到一个带有帖子提要的屏幕。我使用 ListView.builder 从我的数据库中获取帖子列表并创建帖子提要。我的问题是,当提要屏幕最初启动时,ListView 没有加载。一旦我热重新加载应用程序,列表就会加载。我想我的代码中有一个非常明显的小错误,但我就是找不到它。我会将提要屏幕中的所有代码放在下面,请看一下,如果您发现错误,请告诉我。

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);
          }),
    );
  }
}

原因是您需要重建屏幕以在执行异步操作后显示反映的更改(使用 setState 重建 UI)。其次,.forEach 循环不是为承载异步内容而构建的,而且效率低于普通的 for 循环,因此最好更改它。

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:- 您可以使用名为 loading 的变量来显示进度指示器,并在 setState 中获取数据后将其设置为 false。