title: Firestore Pagination
body: <p>I have a question about how to properly paginate queries with Firestore.</p>
  
  <p>By putting the next query into the OnSuccessListener of the previous query, like in the example on the Firestore page, wouldn't it inevitably always trigger a chain reaction that loads all pages at once? Isn't that something we want to avoid with pagination?</p>
  
  <pre><code>// Construct query for first 25 cities, ordered by population
  Query first = db.collection("cities")
          .orderBy("population")
          .limit(25);
  
  first.get()
      .addOnSuccessListener(new OnSuccessListener&lt;QuerySnapshot&gt;() {
          @Override
          public void onSuccess(QuerySnapshot documentSnapshots) {
              // ...
  
              // Get the last visible document
              DocumentSnapshot lastVisible = documentSnapshots.getDocuments()
                      .get(documentSnapshots.size() -1);
  
              // Construct a new query starting at this document,
              // get the next 25 cities.
              Query next = db.collection("cities")
                      .orderBy("population")
                      .startAfter(lastVisible)
                      .limit(25);
  
              // Use the query for pagination
              // ...
          }
      });
  </code></pre>
  
  <p>Source: <a href="https://firebase.google.com/docs/firestore/query-data/query-cursors" rel="nofollow noreferrer">https://firebase.google.com/docs/firestore/query-data/query-cursors</a></p>
  
  <p>This is my approach. I know in a real app I should use a <code>RecyclerView</code>, but I just want to test it on a <code>TextView</code>. I want to load 3 documents with every button click.
  Does it make sense to store the <code>lastResult</code> as a member and then check if it is not null, to see if it is the first query?</p>
  
  <pre><code>public void loadMore(View v) {
      Query query;
      if (lastResult == null) {
          query = notebookRef.orderBy("priority")
                  .orderBy("title")
                  .limit(3);
      } else {
          query = notebookRef.orderBy("priority")
                  .orderBy("title")
                  .startAfter(lastResult)
                  .limit(3);
      }
      query.get().addOnSuccessListener(new OnSuccessListener&lt;QuerySnapshot&gt;() {
          @Override
          public void onSuccess(QuerySnapshot queryDocumentSnapshots) {
              String data = "";
  
              for (QueryDocumentSnapshot documentSnapshot : queryDocumentSnapshots) {
                  Note note = documentSnapshot.toObject(Note.class);
                  note.setDocumentId(documentSnapshot.getId());
  
                  String documentId = note.getDocumentId();
                  String title = note.getTitle();
                  String description = note.getDescription();
                  int priority = note.getPriority();
  
                  data += "ID: " + documentId
                          + "\nTitle: " + title + "\nDescription: " + description
                          + "\nPriority: " + priority + "\n\n";
              }
  
              if (queryDocumentSnapshots.size() &gt; 0) {
                  data += "_____________\n\n";
                  textViewData.append(data);
  
  
                  lastResult = queryDocumentSnapshots.getDocuments()
                          .get(queryDocumentSnapshots.size() - 1);
              }
          }
      });
  }
  </code></pre>