Firebase颤振分页对我不起作用 [英] Flutter pagination with firebase not working for me
问题描述
我尝试了两种可能性,但是firebase数据没有存储在产品列表中。应用页面不返回任何数据,因为产品列表中没有任何内容。下面的列表成功返回了数据。我尝试过的第二个可能性和Consolelog在下面的pastebin链接中:
https: //pastebin.com/DM47YHY6
List< String> foollowingList = [];
List< NetworkImage> _listOfImages =< NetworkImage> [];
List< DocumentSnapshot>产品= []; //存储获取的产品
bool isLoading = true; //跟踪是否获取
bool的产品hasMore = true; //标记是否有更多可用产品
int documentLimit = 10; //每个请求要获取的文档
DocumentSnapshot lastDocument; //标志从最后10条记录中提取的最后一个文档
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()异步{
QuerySnapshot快照=等待以下引用
.document(currentUser.id)
.collection('userFollowing')
.getDocuments();
setState((){
foollowingList = snapshot.documents.map((doc)=> doc.documentID).toList();
});
}
getPosts()async {
for(int i = 0; i 查询q = Firestore .instance
.collection('posts / $ {foollowingList [i]} / userPosts')
.orderBy('ownerId')
.orderBy('timestamp',降序为true)
.limit(documentLimit);
setState((){
isLoading = true;
});
QuerySnapshot querySnapshot =等待q.getDocuments();
print( kjndskjl $ products);
lastDocument = querySnapshot.documents [querySnapshot.documents.length-1];
个产品= querySnapshot.documents;
setState((){
isLoading = false;
});
}
}
getMorePosts()async {
print('get More call');
if(hasMore == false){
return;
} if(hasMore == true){
return;
}
hasMore = true;
for(int i = 0; i< foollowingList.length; i ++){
查询q =等待Firestore.instance
.collection('posts / $ {foollowingList [i]} / userPosts ')
.orderBy('ownerId')
.orderBy('timestamp',降序为true)
.startAfterDocument(lastDocument)
.limit(documentLimit);
QuerySnapshot querySnapshot =等待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
列(子项:[
Expanded(
子代:products.length == 0
?Center(
子代:Text('No Data ...'),
)
:ListView.builder(
控制器:_scrollController,
itemCount:products.length,
itemBuilder :(上下文,索引){
return
FutureBuilder(
future:usersRef.document (products [index] .data ['ownerId'])。get(),
构建器:(上下文,快照){
if(!snapshot.hasData){
return CircularProgress() ;
}
用户user = User.fromDocument(snapshot.data);
return Column(子级:< Widget> [
ListTile(
开头:GestureDetector(
onTap:()=> showProfile(context,profileId:user.id),
子级:CircleAvatar(
backgroundImage:CachedNetworkImageProvider(user.photoUrl),
backgroundColor:Colors.grey,
),
),
标题:GestureDetector(
onTap:()=> showProfile(context,profileId:user.id),
子项:Text(
user.displayName,
样式:TextStyle(
颜色:kText,
fontWeight:FontWeight.bold,
),
),
),
字幕: GestureDetector(
onTap:()=> showProfile(context,profileId:user.id),
child:Text(user.username,
样式:TextStyle(颜色:kIcon),),
),),
cachedNetworkImage(products [index] .data ['mediaUrl']),
Divider(color: kGrey,),
],
);
},
);
在您的第一个代码中
getMorePosts()async {
print('get More call');
if(hasMore == false){
return;
} if(hasMore == true){
return;
}
//其余都是无效代码,如果hasMore是true还是false,您总是返回
....
}
在您的代码段中,它似乎实际上填满了产品列表,但用户为空(在空值上调用了getter'id')
,您确定 User user = User.fromDocument(snapshot.data);
正确解析了数据吗?尝试更改 showProfile(context,profileId:user?.id ?? 1)
只是为了测试它(我不知道id是否应该是int,String等,但是如果是String,请用一些String'Test'更改1)
UPDATE
而不是在 initState
在 getFfollowing
void initState(){
super.initState();
getFfollowing();
// getPosts();这可以在getFfollowing结束之后运行,其中列表为空
_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()异步{
QuerySnapshot快照=等待以下引用
.document(currentUser.id)
.collection('userFollowing')
.getDocuments();
setState((){
foollowingList = snapshot.documents.map((doc)=> doc.documentID).toList();
});
if(foollowingList.isNotEmpty)等待getPosts(); //如果确定将来已完成并且列表已满,请在此处运行
}
诀窍是initState无法运行Future,因此它将尝试按其顺序运行 getFfollowing
和 getPosts
调用,但是将 getPosts
放入 getFfollowing
内,这是异步的,确保您仅在其他代码结束时运行。还要避免在for中使用setState,这会使它不必要地重建很多次,只需将其放在开头和结尾
getPosts ()async {
setState(()=> isLoading = true);
for(int i = 0; i< foollowingList.length; i ++){
查询q = Firestore.instance
.collection('posts / $ {foollowingList [i]} / userPosts' )
.orderBy('ownerId')
.orderBy('timestamp',降序为true)
.limit(documentLimit);
QuerySnapshot querySnapshot =等待q.getDocuments();
print( kjndskjl $ products);
lastDocument = querySnapshot.documents [querySnapshot.documents.length-1];
个产品= querySnapshot.documents;
}
setState(()=> isLoading = false);
}
I tried two posibilities but the firebase data isnt being stored in the products list.The app page returns no data as there is nothing in procucts list. foollowing list returns data succesfully.The second possibilty that i tried and the Consolelog is in this pastebin link below: 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,),
],
);
},
);
![
In your first code
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
....
}
In your Snippet it seems it actually fills the prodcuts list but user is null (The getter 'id' was called on null)
, are you sure User user = User.fromDocument(snapshot.data);
is parsing the data correctly? try changing showProfile(context, profileId: user?.id ?? 1)
just to test it (I don't know if id should be an int, String, etc but in case of String change the 1 with some String 'Test')
UPDATE
Instead of running getPost in initState
run it at the end of 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
}
The trick is that initState cannot run a Future, so it will try to run getFfollowing
and getPosts
in the order they're called, but putting getPosts
inside getFfollowing
, which is async, assure you that it will run only when the other code ends. Also try to avoid using setState inside the for, this will make it rebuild a lot of times unnecesary, just put it at the beginning and end
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);
}
这篇关于Firebase颤振分页对我不起作用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!