issue with initializing List in a Future builder flutter firebase: LateInitializationError: Field 'posts' has not been initialized
issue with initializing List in a Future builder flutter firebase: LateInitializationError: Field 'posts' has not been initialized
我在使用这个 future builder 时遇到了问题,似乎找不到解决方案。我正在尝试创建映射到我创建的自定义 class(“BlogPosts”)的文档列表(“帖子”),但是在尝试使用它时出现以下错误。
错误:
LateInitializationError: Field 'posts' has not been initialized.
堆栈跟踪告诉我生成器内部发生了错误,但我已经初始化了 'posts' 以后
未来的建设者:
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']
);
}
我怀疑这里的 print
语句导致了错误:
builder: (context, snap) {
print(posts);
...
您的构建器被调用了很多次,最初 Future
实际上还没有从 Firestore 中读取数据。
您只想在连接完成后打印:
builder: (context, snap) {
if(snap.connectionState == ConnectionState.done) {
print(posts);
...
但是您处理 Future
的方式似乎也很不对。只是在代码周围放置 Future.wait()
并不会突然让所有异步调用都工作。
您需要将 Future
的数组传递给 Future.wait()
,然后在您的 builder
正文:
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]);
...
所以这里 builder 的 future
属性 得到了两个 futures,snap
保存了数据库中的两个结果。当 snap.connectionState
完成后,您可以访问 snap.data[0]
和 snap.data[1]
以获取结果。
另见:
我发现了我的问题,因为我的代码一直都很好我只是在我的 fromDocument
中有一个拼写错误我的 userId 字符串是 doc['UserId']
并且被上传为 'userId'
只是一个错位的大写。
非常感谢您的帮助
我在使用这个 future builder 时遇到了问题,似乎找不到解决方案。我正在尝试创建映射到我创建的自定义 class(“BlogPosts”)的文档列表(“帖子”),但是在尝试使用它时出现以下错误。
错误:
LateInitializationError: Field 'posts' has not been initialized.
堆栈跟踪告诉我生成器内部发生了错误,但我已经初始化了 'posts' 以后
未来的建设者:
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']
);
}
我怀疑这里的 print
语句导致了错误:
builder: (context, snap) {
print(posts);
...
您的构建器被调用了很多次,最初 Future
实际上还没有从 Firestore 中读取数据。
您只想在连接完成后打印:
builder: (context, snap) {
if(snap.connectionState == ConnectionState.done) {
print(posts);
...
但是您处理 Future
的方式似乎也很不对。只是在代码周围放置 Future.wait()
并不会突然让所有异步调用都工作。
您需要将 Future
的数组传递给 Future.wait()
,然后在您的 builder
正文:
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]);
...
所以这里 builder 的 future
属性 得到了两个 futures,snap
保存了数据库中的两个结果。当 snap.connectionState
完成后,您可以访问 snap.data[0]
和 snap.data[1]
以获取结果。
另见:
我发现了我的问题,因为我的代码一直都很好我只是在我的 fromDocument
中有一个拼写错误我的 userId 字符串是 doc['UserId']
并且被上传为 'userId'
只是一个错位的大写。
非常感谢您的帮助