firebase - 使用firebase进行分页不适合我
问题描述
我尝试了两种可能性,但 firebase 数据没有存储在产品列表中。应用程序页面没有返回数据,因为 procucts 列表中没有任何内容。愚蠢的列表成功返回数据。我尝试的第二个可能性和控制台日志在下面的这个 pastebin 链接中: https ://pastebin.com/DM47YHY6
List<String> foollowingList = [];
List<NetworkImage> _listOfImages = <NetworkImage>[];
List<DocumentSnapshot> products = []; // stores fetched products
bool isLoading = true; // track if products fetching
bool hasMore = true; // flag for more products available or not
int documentLimit = 10; // documents to be fetched per request
DocumentSnapshot lastDocument; // flag for last document from where next 10 records to be fetched
ScrollController _scrollController = ScrollController(); /
void initState() {
super.initState();
getFfollowing();
getPosts();
_scrollController.addListener(() {
double maxScroll = _scrollController.position.maxScrollExtent;
double currentScroll = _scrollController.position.pixels;
double delta = MediaQuery.of(context).size.height * 0.20;
if (maxScroll - currentScroll <= delta) {
getMorePosts();
}
});
}
getFfollowing() async {
QuerySnapshot snapshot = await followingRef
.document(currentUser.id)
.collection('userFollowing')
.getDocuments();
setState(() {
foollowingList = snapshot.documents.map((doc) => doc.documentID).toList();
});
}
getPosts()async{
for( int i=0; i< foollowingList.length; i++) {
Query q = Firestore.instance
.collection('posts/${foollowingList[i]}/userPosts')
.orderBy('ownerId')
.orderBy('timestamp', descending: true)
.limit(documentLimit);
setState(() {
isLoading = true;
});
QuerySnapshot querySnapshot = await q.getDocuments();
print("kjndskjl$products");
lastDocument = querySnapshot.documents[querySnapshot.documents.length - 1];
products = querySnapshot.documents;
setState(() {
isLoading = false;
});
}
}
getMorePosts()async{
print('get more called');
if(hasMore == false){
return;
} if(hasMore == true){
return;
}
hasMore = true;
for( int i=0; i< foollowingList.length; i++) {
Query q = await Firestore.instance
.collection('posts/${foollowingList[i]}/userPosts')
.orderBy('ownerId')
.orderBy('timestamp', descending: true)
.startAfterDocument(lastDocument)
.limit(documentLimit);
QuerySnapshot querySnapshot = await q.getDocuments();
if (querySnapshot.documents.length == 0) {
hasMore = false;
}
lastDocument = querySnapshot.documents[querySnapshot.documents.length - 1];
products.addAll(querySnapshot.documents);
setState(() {
hasMore = false;
print(products);
});
}
}
buildPosts(){
return
Column(children: [
Expanded(
child: products.length == 0
? Center(
child: Text('No Data...'),
)
: ListView.builder(
controller: _scrollController,
itemCount: products.length,
itemBuilder: (context, index) {
return
FutureBuilder(
future: usersRef.document(products[index].data['ownerId']).get(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return circularProgress();
}
User user = User.fromDocument(snapshot.data);
return Column(children: <Widget>[
ListTile(
leading: GestureDetector(
onTap: () => showProfile(context, profileId: user.id),
child: CircleAvatar(
backgroundImage: CachedNetworkImageProvider(user.photoUrl),
backgroundColor: Colors.grey,
),
),
title: GestureDetector(
onTap: () => showProfile(context, profileId: user.id),
child: Text(
user.displayName,
style: TextStyle(
color: kText,
fontWeight: FontWeight.bold,
),
),
),
subtitle: GestureDetector(
onTap: () => showProfile(context, profileId: user.id),
child: Text(user.username,
style: TextStyle(color: kIcon),),
),),
cachedNetworkImage(products[index].data['mediaUrl']),
Divider(color: kGrey,),
],
);
},
);
![
解决方案
在您的第一个代码中
getMorePosts()async{
print('get more called');
if(hasMore == false){
return;
} if(hasMore == true){
return;
}
//The rest is dead code, you always return if hasMore is true or false
....
}
在您的 Snippet 中,它似乎实际上填充了 prodcuts 列表,但 user 为 null (The getter 'id' was called on null)
,您确定User user = User.fromDocument(snapshot.data);
正确解析数据吗?尝试更改showProfile(context, profileId: user?.id ?? 1)
只是为了测试它(我不知道 id 是否应该是 int、String 等,但如果是 String,则使用一些 String 'Test' 更改 1)
更新
而不是在运行 getPostinitState
的末尾运行它getFfollowing
void initState() {
super.initState();
getFfollowing();
//getPosts(); this could run after getFfollowing ends, where the list is empty
_scrollController.addListener(() {
double maxScroll = _scrollController.position.maxScrollExtent;
double currentScroll = _scrollController.position.pixels;
double delta = MediaQuery.of(context).size.height * 0.20;
if (maxScroll - currentScroll <= delta) {
getMorePosts();
}
});
}
getFfollowing() async {
QuerySnapshot snapshot = await followingRef
.document(currentUser.id)
.collection('userFollowing')
.getDocuments();
setState(() {
foollowingList = snapshot.documents.map((doc) => doc.documentID).toList();
});
if(foollowingList.isNotEmpty) await getPosts(); //run it here when you're sure the future is completed and the list is full
}
诀窍是 initState 不能运行 Future,因此它会尝试按照它们被调用的顺序运行,但是放入getFfollowing
内部,它是异步的,确保它只会在其他代码结束时运行。还要尽量避免在for里面使用setState,这样会导致很多次rebuild不必要的,放在开头和结尾就好了getPosts
getPosts
getFfollowing
getPosts()async{
setState(() => isLoading = true);
for( int i=0; i< foollowingList.length; i++) {
Query q = Firestore.instance
.collection('posts/${foollowingList[i]}/userPosts')
.orderBy('ownerId')
.orderBy('timestamp', descending: true)
.limit(documentLimit);
QuerySnapshot querySnapshot = await q.getDocuments();
print("kjndskjl$products");
lastDocument = querySnapshot.documents[querySnapshot.documents.length - 1];
products = querySnapshot.documents;
}
setState(() => isLoading = false);
}
推荐阅读
- apache-spark - 司机无故停止执行者
- sql - psql PGP_SYM_DECRYPT:提示:没有函数匹配给定的名称和参数类型
- c# - 从 C# 中的 DataGridView 读取编码字符串
- sql - 将列类型从文本更改为整数
- php - 如何将列数据转换为表头 laravel
- azure - 如何仅将 Azure DevOps 用于构建部分?以及 jenkins 中的 ci/cd 的其余部分
- c# - 将一个按钮绑定到 3 个不同的 DataGrids,每个 DataGrids 在 TabControl 中
- php - 从php中的变量中删除空间
- rabbitmq - Rabbitmq-如何获得发布方确认消费者已收到消息
- html - 如何在选择选项中插入输入类型=“隐藏”