使用颤动流进行分页

时间:2021-01-09 09:24:11

标签: flutter pagination stream

我已经在我的 flutter 应用程序中实现了一个分页方案,但我不确定它的性能是否友好,以及它是否可能在未来的生产中导致问题,所以我想就它获得建议。 这是我的实现

首先,我使用父小部件中的流提供程序获取数据。


class BuyerSellerPostsPage extends StatefulWidget {

  @override
  _BuyerSellerPostsPageState createState() => _BuyerSellerPostsPageState();
}

class _BuyerSellerPostsPageState extends State<BuyerSellerPostsPage> {

   ...some code here...

   bool isAtBottom = false;
   int postToDisplay=10;

   @override
   void initState() {
     super.initState();
     // Setup the listener.
     _scrollController.addListener(() {
       if (_scrollController.position.atEdge) {
         if (_scrollController.position.pixels == _scrollController.position.maxScrollExtent) {
          setState(() {
            isAtBottom=true;
            postToDisplay+=10;
            print('now true');
          });
         }else{
           setState(() {
             print('now false');
            isAtBottom=false;
           });
         }
       }
     });
   }
  @override
  void dispose(){
     _scrollController.dispose();
     super.dispose();
  }

...some code here..

  @override
  Widget build(BuildContext context) {

    Position coordinates=Provider.of<Position>(context);

...some code here...

        body: SingleChildScrollView(
          controller: _scrollController,
            child: StreamProvider<List<SellerPost>>.value(
              value: SellerDatabaseService(
                  currentLocation: new GeoPoint(coordinates.latitude, coordinates.longitude,)
                  ,filters: _setFilters,
                  selectedCategory: _selectedCategory,
                selectedTag: _selectedTag,
                postsToDisplay: postToDisplay
              ).inRangeSellerPosts ,

                  ...some code here...

                                  );
                                }else{
                                  return Container(
                                  );
                                }
                              },
                            ),
                          ),
                          //post list
                          BSellerPostList(),

                       ...some code here...



  }
}

要显示的初始帖子是 10。 在我的 initstate 中,我对我的滚动控制器使用了一个监听器,这样当用户滚动到底部时,更多的项目(+10)会加载到屏幕上。

在我的流提供程序中,我将 postsToDisplay int 传递给我下面后端的流

  Stream <List<SellerPost>> get inRangeSellerPosts {

    try {
      return sellerPostCollection
          .where("expireTime" , isGreaterThan: DateTime.now())
          .orderBy('expireTime',descending: true)
          .snapshots()
          .map(yieldSellerPosts);
    } catch (e) {
      print(e.toString());
      return null;
    }
  }
 
  List<SellerPost> yieldSellerPosts(QuerySnapshot snapshot) {
    List<String> l = [];
    print(snapshot.documents.length);
    try {
      return snapshot.documents.map((doc) {
        return SellerPost(
         ...some code here...
        );
      }).take(postsToDisplay)
          .toList();
    } catch (e) {
      print(e.toString());
      return null;
    }
  }

我现在获取快照并使用列表中的 take 方法仅获取所需的数字(postsToDisplay)。 这种方法在我的调试模式下工作正常。我不确定它在生产中或使用大型数据集时会如何表现。有人可以仔细检查一下吗,我将不胜感激。

1 个答案:

答案 0 :(得分:0)

我个人使用了之前类似问题中发布的 this 答案的修改版本。 我的实现和其他人的实现都有利有弊。 考虑到您可能只需要 10 个分页项目,他的方法导致您可能永远不需要使用文档的文档更改。另一方面,我的方法不适用于流。它使用 future 来查询文档快照以在您继续时更新列表。

这是示例代码

bool _isRequesting = false;
bool _isFinish = false;
final _scrollController = ScrollController();

List<DocumentSnapshot> _posts = [];
   @override
   void initState() {
     _scrollController.addListener(() {
       if (_scrollController.position.atEdge) {
         if (_scrollController.position.pixels == _scrollController.position.maxScrollExtent) {
           setState(() {
             requestNextPage();
           });
         }
       }
     });
     requestNextPage();
     super.initState();
   }
   void requestNextPage() async {
     try{
     if (!_isRequesting && !_isFinish) {
       QuerySnapshot querySnapshot;
       _isRequesting = true;
       if (_posts.isEmpty) {
           //check if _posts list is empty so that we may render the first list of 10 items.
           querySnapshot = await Firestore.instance
               .collection('sellerPost')
               .limit(10)
               .getDocuments();

       } else {
        //if _posts list is not empty it means we have already rendered the first  10 items so we start querying from where we left off to avoid repetition.
           querySnapshot = await Firestore.instance
               .collection('sellerPost')
               .startAfterDocument(_posts[_posts.length - 1])
               .limit(10)
               .getDocuments();

       }

       if (querySnapshot != null) {
         int oldSize = _posts.length;
         _posts.addAll(querySnapshot.documents);
         int newSize = _posts.length;
         if (oldSize == newSize) {
           _isFinish = true;
         }
       _isRequesting = false;

     }else{
       _isFinish = false;
       _isRequesting = false;
     }
     }catch(e){
       print(e.toString());
     }

   }

因此,在上面的代码中,我使用滚动控制器来检测用户何时使用分页项目(例如 10 个帖子)滚动到页面底部。此事件触发我的函数 requestNextPage(); 请注意,在 inititState 上,我们还调用 requestNextPage(); 来呈现最初的 10 个帖子。 所以现在,每次检测到滚动到底部时,都会添加 10 个额外的帖子 _posts