【问题标题】:how can I add lazy loading to this list?如何将延迟加载添加到此列表中?
【发布时间】:2020-08-06 20:26:19
【问题描述】:

这就是我从 firebase firestore 获取 postList 中的帖子的方式,我需要一个可以在滚动上获取更多帖子的函数。下一组帖子必须在此初始列表中显示的最后一个帖子之后开始,并在用户滚动时添加到此列表中,只要 Firestore 中有帖子。

class _FeedScreenState extends State<FeedScreen> {
  List<Post> _posts = [];
   ScrollController _controller = ScrollController();

  @override
  void initState() {
    super.initState();
    _setupFeed();
     _controller.addListener(_scrollListener);
  }

_scrollListener() {
    setState(() {
      if (_controller.position.atEdge) {
        if (_controller.position.pixels == 0) {


        } else {
          _getMore();

        }
      }
    });
  }
  _setupFeed() async {
    List<Post> posts = await DatabaseService.getFeedPosts(widget.currentUserId);
    setState(() {
      _posts = posts;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Colors.white,
        title: Text(
          'New List',
          style: TextStyle(
            color: Colors.black,
            fontSize: 35.0,
          ),
        ),
      ),
      body: RefreshIndicator(
        onRefresh: () => _setupFeed(),
        child: ListView.builder(
          controller: _controller,
          itemCount: _posts.length,
          itemBuilder: (BuildContext context, int index) {
            Post post = _posts[index];
            return FutureBuilder(
              future: DatabaseService.getUserWithId(post.authorId),
              builder: (BuildContext context, AsyncSnapshot snapshot) {
                if (!snapshot.hasData) {
                  return SizedBox.shrink();
                }
                User author = snapshot.data;
                return PostView(
                  currentUserId: widget.currentUserId,
                  post: post,
                  author: author,
                );
              },
            );
          },
        ),
      ),
    );
  }
}

这就是我获取帖子列表的方式

static Future<List<Post>> getFeedPosts(String userId) async {
    QuerySnapshot feedSnapshot = await feedsRef
        .document(userId)
        .collection('userFeed')
        .orderBy('timestamp', descending: true)
        .limit(30)
        .getDocuments();
    List<Post> posts =
        feedSnapshot.documents.map((doc) => Post.fromDoc(doc)).toList();
    return posts;
  }

【问题讨论】:

  • 当前行为是什么?没有添加帖子?还是帖子列表完全改变了?
  • 我将限制设置为 30,因此 postList 中加载了 30 个帖子,但是如何在滚动时加载更多帖子?因为如果我不设置限制,那么它会加载集合中的所有帖子。

标签: flutter


【解决方案1】:

na2axl 的答案几乎是正确的。我将在这里添加一个解释和示例,说明如何使用startAfter()

如果您检查documentation on pagination,您将看到您需要使用startAfter() 引用您使用的任何过滤器。在您的情况下,您使用timestamp 进行订购,因此您的下一个查询应如下所示:

static Future<List<Post>> getNextFeedPosts(String userId, TimeStamp timestamp) async {
    QuerySnapshot feedSnapshot = await feedsRef
        .document(userId)
        .collection('userFeed')
        .orderBy('timestamp', descending: true)
        //Here you need to let Firebase know which is the last document you fetched
        //using its timesTamp
        .startAfter(timestamp)
        .limit(30)
        .getDocuments();
    List<Post> posts =
        feedSnapshot.documents.map((doc) => Post.fromDoc(doc)).toList();
    return posts;
  }

这意味着您的下一个查询仍将按timestamp 排序,但检索到的第一个文档将startAfter 上的timestamp 之后

我希望这会有所帮助,但是,您可以查看文档,因为还有其他示例!

【讨论】:

  • 我如何提及最后一个文档的时间戳,因为无法知道确切的时间戳,或者我该怎么做?如果这听起来很蹩脚,我很抱歉,我只是这里的初学者。:)
  • 当您按“时间戳”对文档进行排序时,这意味着它已经存储在您的数据库中。如果您检查从 Firebase 检索的最后一个文档,它将有一个时间戳,您可以在下一个查询中将其与 startAfter 一起使用以下载接下来的 30 个结果。
  • 我阅读了文档并尝试相应地提及时间戳,但它在控制台中出现了一些错误,如果您能展示如何在这种情况下提及最后一个文档,那就太好了。
  • QueryDocumentSnapshot lastDoc = docs.get(docs.size() - 1); '查询 secondPage = city.orderBy("population").startAfter(lastDoc).limit(25);'这就是它在文档中的显示方式
  • 你的 Post 对象有 DateTime 吗?
【解决方案2】:

我认为这样做可以解决您的问题:

您必须编辑您的 getFeedPosts 以收集从给定索引开始的帖子:

我对 FireStore 不熟悉,我在 docs 上找到了 startAt() 方法

编辑:我误解了 Firestore 的概念,所以我按照 Francisco Javier Snchez 的建议将 startAt() 更改为 startAfter()

static Future<List<Post>> getFeedPosts(String userId, TimeStamp start) async {
  QuerySnapshot feedSnapshot = await feedsRef
      .document(userId)
      .collection('userFeed')
      .orderBy('timestamp', descending: true)
      .startAfter(start)
      .limit(30)
      .getDocuments();
  List<Post> posts =
      feedSnapshot.documents.map((doc) => Post.fromDoc(doc)).toList();
  return posts;
}

现在可以这样查询了:

_getMore() async {
  // You have to give the timestamp of the last post here
  // Change this line by the right way...
  List<Post> posts = await DatabaseService.getFeedPosts(widget.currentUserId, _posts[_posts.length - 1].timestamp);
  setState(() {
    // Do += instead of =, += will add fetched posts to the current list, = will overwrite the whole list
    _posts += posts;
  });
}

希望这会有所帮助!

【讨论】:

  • 但是这将如何获取从最初加载列表中的最后一个帖子开始的帖子?
  • @notabot 它将使用当前加载的列表长度(最初为 30)在 30 个帖子之后获取接下来的 30 个帖子。当您第二次滚动到末尾时,加载的帖子数将为 60,因此调用此方法将获取下一个帖子的 30 个,60 个帖子之后,依此类推...
  • @na2axl 只是为了让您知道,startAt 和 startAfter 指的是您在 orderBy 中使用的字段。如果您尝试将 startIndex 提供给时间戳,它将失败。
  • @FranciscoJavierSnchez 对不起,我误解了这个概念,我已经更新了我的答案
  • 但是我如何提及 startAfter(此处最后一个被感染文档的时间戳)?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-02-21
  • 1970-01-01
  • 2020-11-05
  • 2021-01-08
  • 2021-08-23
  • 1970-01-01
相关资源
最近更新 更多