首页 > 解决方案 > 使用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,),
                  ],

                  );
                },
              );

在此处输入图像描述![

标签: firebaseflutterdartgoogle-cloud-firestore

解决方案


在您的第一个代码中

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不必要的,放在开头和结尾就好了getPostsgetPostsgetFfollowing

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);
}

推荐阅读