【问题标题】:Pagination with streams in flutter在颤动中使用流进行分页
【发布时间】:2021-04-14 20:56:49
【问题描述】:

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

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


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)。 此方法在我的调试模式下运行良好。我不确定它在生产或大型数据集中的表现如何。有人可以仔细检查一下吗,我将不胜感激。

【问题讨论】:

  • 我正在加快 StreamProvider 的速度,分页会引导我找到你的帖子。我看到你在yieldSellerPosts 中使用了take。如果我理解正确,那将加载您的第一页。您如何加载第二页?
  • 首先,该方法的性能和成本都很差,因为分页是在客户端(移动)上完成的,这意味着我浪费了 CPU 时间来查询 100 多个文档来渲染其中的 10 个。无论如何,显示更多帖子的技巧是在 _scrollController 监听器中,对于每个监听的事件,我都做了 posts+=10 以将新值设为 20,依此类推。再说一遍,这是一个糟糕的方法。
  • 感谢@Bright。所以你有一些让你满意的工作吗?如果是这样,你介意用你工作的代码示例来回答你的问题吗?这将对我和其他任何发现您的问题的人有很大帮助。我已经使用 Flutter 18 个月了,分页流一直是我遇到的最具挑战性的问题。
  • @buttonsrtoys 让我发布我使用的最终方法

标签: flutter pagination stream


【解决方案1】:

我个人使用了以前类似问题中发布的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

【讨论】:

  • 感谢您的帖子!我现在正在调查,会跟进
猜你喜欢
  • 2021-09-17
  • 2019-05-15
  • 2020-04-01
  • 1970-01-01
  • 2020-03-30
  • 2018-07-17
  • 2022-11-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多