【问题标题】:issue with initializing List in a Future builder flutter firebase: LateInitializationError: Field 'posts' has not been initialized在 Future builder flutter firebase 中初始化 List 的问题:LateInitializationError: Field 'posts' has not been initialized
【发布时间】:2026-01-08 19:35:01
【问题描述】:

我在使用这个未来的构建器时遇到了问题,似乎无法找到解决方案。我正在尝试创建一个映射到我创建的自定义类(“BlogPosts”)的文档列表(“帖子”),但是在尝试使用它时出现以下错误。

错误:

LateInitializationError: Field 'posts' has not been initialized.

堆栈跟踪告诉我错误正在生成器内部发生,但我已经在未来初始化了“帖子”

未来的建设者:

late User user;
late Userdata userdata;
CollectionReference usersRef = FirebaseFirestore.instance.collection('users');
CollectionReference postsRef = FirebaseFirestore.instance.collection('posts');
late List<BlogPost> posts;

FutureBuilder(
          future: Future.wait([
            usersRef.doc(user.uid).get().then((doc) {
            userdata = Userdata.fromDocument(doc);
            }),
            postsRef.get().then((val) {
              posts = val.docs.map((doc) => BlogPost.fromDocument(doc)).toList();
            })
    ]),
          builder: (context, snap) {
            print(posts);
            if(snap.connectionState == ConnectionState.done) {
              return ListView.builder(
                physics: BouncingScrollPhysics(),
                  itemCount: 3,
                  itemBuilder: (context, index) {
                  return Text(userdata.displayName);
                  }
              );
            } else {
              return Center(
                child: Text('Loading')
              );
            }
          }
        )

完整代码:

late User user;
late Userdata userdata;
CollectionReference usersRef = FirebaseFirestore.instance.collection('users');
CollectionReference postsRef = FirebaseFirestore.instance.collection('posts');

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

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

class _HomeScreenState extends State<HomeScreen> {
  final auth = FirebaseAuth.instance;
  late List<BlogPost> posts;

  @override
  Widget build(BuildContext context) {
    user = auth.currentUser!;
    Color getColor(Set<MaterialState> states) {
      const Set<MaterialState> interactiveStates = <MaterialState>{
        MaterialState.pressed,
        MaterialState.hovered,
        MaterialState.focused,
      };
      if (states.any(interactiveStates.contains)) {
        return Colors.blue.shade900;
      }
      return Colors.blue.shade600;
    }
    return Scaffold(
      floatingActionButton: FloatingActionButton(
        backgroundColor: Colors.blue,
        child: Icon(
          Icons.add,
          color: Colors.white,
        ),
        onPressed: (){
          Navigator.push(context, MaterialPageRoute(builder: (_) => Upload()));
        },
      ),
        appBar: AppBar(
          backgroundColor: Colors.grey[600],
          actions: [
            TextButton(
              child: Text(
                'Logout',
                style: TextStyle(color: Colors.black),
              ),
              onPressed: () {
                auth.signOut();
                Navigator.of(context).pushReplacement(MaterialPageRoute(builder: (context) => LoginScreen()));
              },
              style: ButtonStyle(
                  backgroundColor: MaterialStateProperty.resolveWith(getColor)
              ),
            ),
          ],
        ),
        // body: Center(
        //   child: Text(user.uid)
        // ),

        body: FutureBuilder(
          future: Future.wait([
            usersRef.doc(user.uid).get().then((doc) {
            userdata = Userdata.fromDocument(doc);
            }),
            postsRef.get().then((val) {
              posts = val.docs.map((doc) => BlogPost.fromDocument(doc)).toList();
            })
    ]),
          builder: (context, snap) {
            print(posts);
            if(snap.connectionState == ConnectionState.done) {
              return ListView.builder(
                physics: BouncingScrollPhysics(),
                  itemCount: 3,
                  itemBuilder: (context, index) {
                  return Text(userdata.displayName);
                  }
              );
            } else {
              return Center(
                child: Text('Loading')
              );
            }
          }
        )
    );
  }
}

class Userdata {

  final String uid;
  final String email;
  final String displayName;


  Userdata(this.uid, this.email,  this.displayName);

  factory Userdata.fromDocument(DocumentSnapshot doc) {
    return Userdata(
        doc['uid'],
        doc['email'],
        doc['displayName']
    );
  }
}

class BlogPost {
  String displayName;
  String postmsg;
  String postId;
  String UserId;

  BlogPost(this.displayName, this.postmsg, this.postId, this.UserId);

  factory BlogPost.fromDocument(DocumentSnapshot doc) {
    return BlogPost(
        doc['displayName'],
        doc['postmsg'],
        doc['postId'],
        doc['UserId']
    );
  }

【问题讨论】:

    标签: firebase flutter flutter-futurebuilder


    【解决方案1】:

    我怀疑这里的print 语句导致了错误:

    builder: (context, snap) {
      print(posts);
      ...
    

    您的构建器被多次调用,最初 Future 实际上还没有从 Firestore 读取数据。

    您只想在连接完成后打印:

    builder: (context, snap) {
      if(snap.connectionState == ConnectionState.done) {
        print(posts);
        ...
    

    但是你处理Future 的方式似乎也很不正常。只是将Future.wait() 放在代码周围并不会突然使其中的所有异步调用都工作。

    您需要将Futures 数组传递给Future.wait(),然后在builder 正文中使用来自snap AsyncSnapshot 的这些期货的结果:

    FutureBuilder(
      future: Future.wait([
        usersRef.doc(user.uid).get().then((doc) => Userdata.fromDocument(doc)),
        postsRef.get().then((val) => val.docs.map((doc) => BlogPost.fromDocument(doc)).toList()))
      ]),
      builder: (context, snap) {
        if(snap.connectionState == ConnectionState.done) {
          if (snap.data[1] != null) print(snap.data[1]);
          ...
    

    所以这里构建器的future 属性获得两个期货,snap 保存来自数据库的两个结果。当snap.connectionState完成后,您可以访问snap.data[0]snap.data[1]获取结果。

    另见:

    【讨论】:

    • 我把它移到里面了,我仍然遇到同样的错误
    • snap.data[0] 给我一个错误:“当我添加空检查或“ ?”我被告知操作员没有定义
    • 嗯...在这种情况下,您可能需要打印 snap.data 以查看其类型和值。
    • 它只是返回空值。我确保它使用测试文档连接到 firebase 并且工作正常,所以我不确定为什么这段代码没有获取帖子数据
    【解决方案2】:

    我发现了我的问题,因为在我的fromDocument 中出现拼写错误的整个过程中,我的代码都很好,我的 userId 字符串是doc['UserId'],并且上传为'userId',只是一个放错了大写字母。

    非常感谢您的帮助

    【讨论】: