列表为空(Flutter)
List is Empty (Flutter)
我在 Flutter 中创建一个列表并将其显示在一个列中,当我 运行 它只是空的,当我打印列表时它只打印一个数组
I/flutter (24613): []
我正在使用此代码创建列表:-
myFunction() {
return StreamBuilder(
stream:
users.orderBy('timestamp', descending: true).limit(30).snapshots(),
builder: (context, snapshot) {
List<UserList> usersList = [];
snapshot.data.documents.forEach((doc) {
User user = User.fromDocument(doc);
UserList userList = UserList(user);
usersList.add(userList);
});
return Column (children: usersList);
}
),
}
这是我的用户Class:-
class User {
final String id;
final String username;
final String email;
final String photoUrl;
User({
this.id,
this.username,
this.email,
this.photoUrl,
});
factory User.fromDocument(DocumentSnapshot doc) {
return User(
id: doc.data()['id'],
username: doc.data()['username'],
email: doc.data()['email'],
photoUrl: doc.data()['photoUrl'],
);
}
}
代码没有显示错误,列没有显示,而且当我打印列表的长度时,它显示为零:-
I/flutter (24613): 0
可能是什么问题??
这是因为您必须等待 json 才能真正解析到飞镖模型。第二件事是 forEach 方法是同步的,它不等待异步操作完成,这就是你的列表为空的原因。
所以问题有很多不同的方法可以使列表在 flutter 中异步工作。
列在获取数据之前显示数据,因此显示为空列表。为此,在获取数据后根据您的状态管理类型(提供程序中的“notifylisteners”)使用 setstate,因此屏幕将更新,列也会显示更新后的列表。
正如'Ashutosh patole'所说,'forEach'方法不等待迭代完成。
我觉得是因为这个原因,虽然你做了一个'usersList',
在 'usersList'.
中构建小部件时没有数据
要解决此问题,您最好将 'forEach' 更改为 'for'。
void main() async {
List<String> data = [ 'a', 'b', 'c'];
List<String> result = [];
data.forEach((data) async {
await Future.delayed(Duration(seconds: 1));
result.add(data);
});
print(result);
await Future.delayed(Duration(seconds: 3));
print(result);
print('-----------------');
result = [];
for (var item in data) {
await Future.delayed(Duration(seconds: 1));
result.add(item);
}
print(result);
await Future.delayed(Duration(seconds: 3));
print(result);
}
在您的代码中,您可以进行如下更改。
List<UserList> usersList = [];
for (var doc in snapshot.data.documents) {
User user = User.fromDocument(doc);
UserList userList = UserList(user);
usersList.add(userList);
}
我不太确定你是如何处理变量范围的。
这是我的最小可重现代码,可以让您了解如何将项目添加到列表中。
class MyPage extends StatefulWidget {
@override
_MyPageState createState() => _MyPageState();
}
class _MyPageState extends State<MyPage> {
final List<Widget> _list = [FlutterLogo()];
@override
void initState() {
super.initState();
Timer.periodic(Duration(seconds: 1), (timer) {
if (timer.tick >= 2) timer.cancel();
setState(() => _list.add(FlutterLogo()));
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Column(children: _list),
);
}
}
调用数据前,检查所有字段:
加个print()
看看问题出在哪里
FutureBuilder<DocumentSnapshot>(
future: users.doc(documentId).get(),
builder:
(BuildContext context, AsyncSnapshot<DocumentSnapshot> snapshot) {
//This
if (snapshot.hasError) {
return Text("Something went wrong");
}
print(snapshot.data);
//This
if (snapshot.hasData && !snapshot.data!.exists) {
return Text("Document does not exist");
}
print(snapshot.data);
//This
if (snapshot.connectionState == ConnectionState.done) {
Map<String, dynamic> data = snapshot.data!.data() as Map<String, dynamic>;
return Text("Full Name: ${data['full_name']} ${data['last_name']}");
}
return Text("loading");
},
);
这就是我通常use.Try出的这个!请平衡代码中的括号
FutureBuilder(
future: users.orderBy('timestamp', descending: true).limit(30),
builder: (BuildContext context, AsyncSnapshot<List<User>> snapshot) {
List<User>ulist=snapshot.data;
return ListView.builder(
shrinkWrap: true,
padding: EdgeInsets.only(top: 25,bottom: 35),
itemCount: evlist==null?0:evlist.length,
itemBuilder: (BuildContext context, int index) {
String evtime=evlist[index].fromdate.substring(11,16);
String ontime=evlist[index].fromdate.substring(0,16);
return Container(
decoration: BoxDecoration(
border: Border.all(width: 1.8,color: Colors.indigo[900]),
borderRadius: BorderRadius.circular(12.0),
color: Colors.grey[200]
),
margin:
const EdgeInsets.symmetric(horizontal: 18.0, vertical: 4.0),
child: ListTile(
leading: Icon(Icons.notifications),
title: Text(ulist[index].username.toString()),
subtitle:Text("next data"),
),
);
},
);
我想我们需要稍微调整您的一些代码以使逻辑正常工作。 :)
builder
param 应该用 Type 指定,否则它将是 dynamic
类型。在这种情况下,为了安全起见,它将是 QuerySnapshot
。所以,
builder: (context, snapshot)
在您的代码中变为
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot)
.
接下来,不需要循环遍历 foreach
,您可以尝试下面的方法。
snapshot.data.docs.map((document) { .... }
您代码中的 snapshot.data.documents
不是获取 Firestore 文档的有效方式。请参考official doc
并且您需要 return 来自 builder
的 widget
,您已正确完成。但是,您错误地将 List<UserList>
传递给了 Column
,而 List<Widget>
return Column (children: usersList);
在这里我可以看到你传递的是 usersList
,它的类型是 List<UserList>
。因此,您可以将 Column
替换为 ListView
或类似的其他 widget
,因为 Column
不支持 scroll
。
So combining all these bits and pieces you will get the below snippet.
return StreamBuilder(
stream: FirebaseFirestore.instance
.collection('users')
.orderBy('timestamp', descending: true)
.limit(30)
.snapshots(), // Just for simplicity.
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
//When there is no data returned from the firebase.
if (!snapshot.hasData) {
return Center(
child: CircularProgressIndicator(),
);
}
return ListView(
children: snapshot.data.docs.map((document) {
return Text("Title: " + document['username']);
}).toList(),
);
},
);
为简单起见,我 return 编辑了 Text
小部件。您可以在那里实现自己的 UI。
注意:这是基本的工作示例,您需要像使用模型一样进行相应的微调类,而不是根据您的要求直接访问。
您的代码
myFunction() {
return StreamBuilder(
stream:
users.orderBy('timestamp', descending: true).limit(30).snapshots(),
builder: (context, snapshot) {
List<UserList> usersList = [];
snapshot.data.documents.forEach((doc) {
User user = User.fromDocument(doc);
UserList userList = UserList(user);
usersList.add(userList);
});
return Column (children: usersList);
}
),
}
我在 Flutter 中创建一个列表并将其显示在一个列中,当我 运行 它只是空的,当我打印列表时它只打印一个数组
I/flutter (24613): []
我正在使用此代码创建列表:-
myFunction() {
return StreamBuilder(
stream:
users.orderBy('timestamp', descending: true).limit(30).snapshots(),
builder: (context, snapshot) {
List<UserList> usersList = [];
snapshot.data.documents.forEach((doc) {
User user = User.fromDocument(doc);
UserList userList = UserList(user);
usersList.add(userList);
});
return Column (children: usersList);
}
),
}
这是我的用户Class:-
class User {
final String id;
final String username;
final String email;
final String photoUrl;
User({
this.id,
this.username,
this.email,
this.photoUrl,
});
factory User.fromDocument(DocumentSnapshot doc) {
return User(
id: doc.data()['id'],
username: doc.data()['username'],
email: doc.data()['email'],
photoUrl: doc.data()['photoUrl'],
);
}
}
代码没有显示错误,列没有显示,而且当我打印列表的长度时,它显示为零:-
I/flutter (24613): 0
可能是什么问题??
这是因为您必须等待 json 才能真正解析到飞镖模型。第二件事是 forEach 方法是同步的,它不等待异步操作完成,这就是你的列表为空的原因。
列在获取数据之前显示数据,因此显示为空列表。为此,在获取数据后根据您的状态管理类型(提供程序中的“notifylisteners”)使用 setstate,因此屏幕将更新,列也会显示更新后的列表。
正如'Ashutosh patole'所说,'forEach'方法不等待迭代完成。
我觉得是因为这个原因,虽然你做了一个'usersList',
在 'usersList'.
要解决此问题,您最好将 'forEach' 更改为 'for'。
void main() async {
List<String> data = [ 'a', 'b', 'c'];
List<String> result = [];
data.forEach((data) async {
await Future.delayed(Duration(seconds: 1));
result.add(data);
});
print(result);
await Future.delayed(Duration(seconds: 3));
print(result);
print('-----------------');
result = [];
for (var item in data) {
await Future.delayed(Duration(seconds: 1));
result.add(item);
}
print(result);
await Future.delayed(Duration(seconds: 3));
print(result);
}
在您的代码中,您可以进行如下更改。
List<UserList> usersList = [];
for (var doc in snapshot.data.documents) {
User user = User.fromDocument(doc);
UserList userList = UserList(user);
usersList.add(userList);
}
我不太确定你是如何处理变量范围的。 这是我的最小可重现代码,可以让您了解如何将项目添加到列表中。
class MyPage extends StatefulWidget {
@override
_MyPageState createState() => _MyPageState();
}
class _MyPageState extends State<MyPage> {
final List<Widget> _list = [FlutterLogo()];
@override
void initState() {
super.initState();
Timer.periodic(Duration(seconds: 1), (timer) {
if (timer.tick >= 2) timer.cancel();
setState(() => _list.add(FlutterLogo()));
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Column(children: _list),
);
}
}
调用数据前,检查所有字段:
加个print()
看看问题出在哪里
FutureBuilder<DocumentSnapshot>(
future: users.doc(documentId).get(),
builder:
(BuildContext context, AsyncSnapshot<DocumentSnapshot> snapshot) {
//This
if (snapshot.hasError) {
return Text("Something went wrong");
}
print(snapshot.data);
//This
if (snapshot.hasData && !snapshot.data!.exists) {
return Text("Document does not exist");
}
print(snapshot.data);
//This
if (snapshot.connectionState == ConnectionState.done) {
Map<String, dynamic> data = snapshot.data!.data() as Map<String, dynamic>;
return Text("Full Name: ${data['full_name']} ${data['last_name']}");
}
return Text("loading");
},
);
这就是我通常use.Try出的这个!请平衡代码中的括号
FutureBuilder(
future: users.orderBy('timestamp', descending: true).limit(30),
builder: (BuildContext context, AsyncSnapshot<List<User>> snapshot) {
List<User>ulist=snapshot.data;
return ListView.builder(
shrinkWrap: true,
padding: EdgeInsets.only(top: 25,bottom: 35),
itemCount: evlist==null?0:evlist.length,
itemBuilder: (BuildContext context, int index) {
String evtime=evlist[index].fromdate.substring(11,16);
String ontime=evlist[index].fromdate.substring(0,16);
return Container(
decoration: BoxDecoration(
border: Border.all(width: 1.8,color: Colors.indigo[900]),
borderRadius: BorderRadius.circular(12.0),
color: Colors.grey[200]
),
margin:
const EdgeInsets.symmetric(horizontal: 18.0, vertical: 4.0),
child: ListTile(
leading: Icon(Icons.notifications),
title: Text(ulist[index].username.toString()),
subtitle:Text("next data"),
),
);
},
);
我想我们需要稍微调整您的一些代码以使逻辑正常工作。 :)
builder
param 应该用 Type 指定,否则它将是 dynamic
类型。在这种情况下,为了安全起见,它将是 QuerySnapshot
。所以,
builder: (context, snapshot)
在您的代码中变为
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot)
.
接下来,不需要循环遍历 foreach
,您可以尝试下面的方法。
snapshot.data.docs.map((document) { .... }
您代码中的 snapshot.data.documents
不是获取 Firestore 文档的有效方式。请参考official doc
并且您需要 return 来自 builder
的 widget
,您已正确完成。但是,您错误地将 List<UserList>
传递给了 Column
,而 List<Widget>
return Column (children: usersList);
在这里我可以看到你传递的是 usersList
,它的类型是 List<UserList>
。因此,您可以将 Column
替换为 ListView
或类似的其他 widget
,因为 Column
不支持 scroll
。
So combining all these bits and pieces you will get the below snippet.
return StreamBuilder(
stream: FirebaseFirestore.instance
.collection('users')
.orderBy('timestamp', descending: true)
.limit(30)
.snapshots(), // Just for simplicity.
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
//When there is no data returned from the firebase.
if (!snapshot.hasData) {
return Center(
child: CircularProgressIndicator(),
);
}
return ListView(
children: snapshot.data.docs.map((document) {
return Text("Title: " + document['username']);
}).toList(),
);
},
);
为简单起见,我 return 编辑了 Text
小部件。您可以在那里实现自己的 UI。
注意:这是基本的工作示例,您需要像使用模型一样进行相应的微调类,而不是根据您的要求直接访问。
您的代码
myFunction() {
return StreamBuilder(
stream:
users.orderBy('timestamp', descending: true).limit(30).snapshots(),
builder: (context, snapshot) {
List<UserList> usersList = [];
snapshot.data.documents.forEach((doc) {
User user = User.fromDocument(doc);
UserList userList = UserList(user);
usersList.add(userList);
});
return Column (children: usersList);
}
),
}