0

On working around to learn firebase firestore for an example from GitHub friendly eat app

I thought to implement pagination to limiting nodes for 10

private static final int LIMIT = 10;

in the firestore example app the mAdapter loads data/nodes as below

mFirestore = FirebaseFirestore.getInstance();

    // Get ${LIMIT} restaurants
    mQuery = mFirestore.collection("restaurants")
            .orderBy("avgRating", Query.Direction.DESCENDING)
            .limit(LIMIT);

    // RecyclerView
    mAdapter = new RestaurantAdapter(mQuery, this) {
        @Override
        protected void onDataChanged() {
            // Show/hide content if the query returns empty.
            if (getItemCount() == 0) {
                mRestaurantsRecycler.setVisibility(View.GONE);
                mEmptyView.setVisibility(View.VISIBLE);
            } else {
                mRestaurantsRecycler.setVisibility(View.VISIBLE);
                mEmptyView.setVisibility(View.GONE);
            }
        }

        @Override
        protected void onError(FirebaseFirestoreException e) {
            // Show a snackbar on errors
            Snackbar.make(findViewById(android.R.id.content),
                    "Error: check logs for info.", Snackbar.LENGTH_LONG).show();
        }
    };

    mRestaurantsRecycler.setLayoutManager(new LinearLayoutManager(this));
    mRestaurantsRecycler.setAdapter(mAdapter);

    // Filter Dialog
    mFilterDialog = new FilterDialogFragment();
}

and

@Override
public void onStart() {
    super.onStart();

    // Start sign in if necessary
    if (shouldStartSignIn()) {
        startSignIn();
        return;
    }

    // Apply filters
    onFilter(mViewModel.getFilters());

    // Start listening for Firestore updates
    if (mAdapter != null) {
        mAdapter.startListening();
    }
}

on firestore docs says about to paginate

// Construct query for first 25 cities, ordered by population
    Query first = db.collection("cities")
            .orderBy("population")
            .limit(25);

    first.get()
            .addOnSuccessListener(new OnSuccessListener<QuerySnapshot>() {
                @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
                    // ...
                }
            });

combining those above codes how should I implement paginate to load more than 10 nodes to load when I scroll to the bottom of the recycler view

// Use the query for pagination

// ...

Update: I am working based on firestore doc about Paginate query and taking look at a possible duplicate of another question I did not get it to done working

Thank you

Community
  • 1
  • 1
Thippesha S
  • 21
  • 1
  • 8
  • This question had been duped incorrectly in the past, but it is now duped correctly. – robsiemb Nov 29 '19 at 18:14
  • I think you might be interested in this article, [How to paginate Firestore using Paging 3 on Android?](https://medium.com/firebase-tips-tricks/how-to-paginate-firestore-using-paging-3-on-android-c485acb0a2df). – Alex Mamo Jan 25 '21 at 18:34

2 Answers2

0

Here I found solution around but not better one, if is there any better way please post

by saving RecyclerView state before loading more nodes and reloading RecyclerView state after increasing the limit

private static final int LIMIT = 10;

Changed to

private int LIMIT = 10;

when recyclerView is scrolled to the bottom

mRestaurantsRecycler.addOnScrollListener(new RecyclerView.OnScrollListener() {

        @Override
        public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
            super.onScrolled(recyclerView, dx, dy);

            final int mLastVisibleItemPosition = mManager.findLastVisibleItemPosition();

            if ( mLastVisibleItemPosition == (LIMIT-1)) {
                LIMIT = LIMIT*2;
                showSpotDialog();

                // save RecyclerView state
                mBundleRecyclerViewState = new Bundle();
                Parcelable listState = mRestaurantsRecycler.getLayoutManager().onSaveInstanceState();
                mBundleRecyclerViewState.putParcelable(KEY_RECYCLER_STATE, listState);

                loadMore(query);
                new Handler().postDelayed(new Runnable() {

                    @Override
                    public void run() {

                        // restore RecyclerView state
                        if (mBundleRecyclerViewState != null) {
                            Parcelable listState = mBundleRecyclerViewState.getParcelable(KEY_RECYCLER_STATE);
                            mRestaurantsRecycler.getLayoutManager().onRestoreInstanceState(listState);
                        }

                        hideSpotDialog();
                    }

                }, 500);

            }
        }
    });

it looks very unusual when nodes are loaded after the limit, but no way for now... and yes I am looking for loading more nodes without flaws

Thippesha S
  • 21
  • 1
  • 8
0

I have extended the FirestoreAdapter as followed:

  1. Keep track DocumentSnapshots identifier.
private Set<String> mIdentifier = new HashSet<>();
  1. Add a new public method for pagination, as i expect the rest of the query to remain the same, the given query does not need to be changed
/**
 * Extends the query to load even more data rows. This method will do nothing if the query has
 * not yet been set.
 * @param limit the new limit
 */
public void paginate(long limit) {
    if (mQuery != null) {
        if (mRegistration != null) {
            mRegistration.remove();
            mRegistration = null;
        }
        // Expect the query to stay the same, only the limit will change
        mQuery = mQuery.limit(limit);
        startListening();
    }
}
  1. Clear the identifier in the setQuery(Query) method by calling mIdentifier.clear()
  2. Adopt the onDocumentAdded(DocumentChange) and the onDocumentRemoved(DocumentChange) as followed
protected void onDocumentAdded(DocumentChange change) {
    if (!mIdentifier.contains(change.getDocument().getId())) {
        mSnapshots.add(change.getNewIndex(), change.getDocument());
        mIdentifier.add(change.getDocument().getId());
        notifyItemInserted(change.getNewIndex());
    }
}
protected void onDocumentRemoved(DocumentChange change) {
    mSnapshots.remove(change.getOldIndex());
    mIdentifier.remove(change.getDocument().getId());
    notifyItemRemoved(change.getOldIndex());
}
  1. For the onScrolling listener i stick to this guide: Endless Scrolling with AdapterViews and RecyclerView
  • Thank you... Looks good but I need time interpret myself and to implement, Definitely will try this one – Thippesha S Dec 28 '17 at 13:42
  • Hello @Peter A, I am using firebase firestore UI and tried above code this line below `getSnapshots().add(change.getNewIndex(), change.getNewIndex());` showing error **_Wrong 2nd argument type. Found: 'com.google.firebase.firestore.DocumentSnapshot', required: 'com.domain.appname.model'_** – Thippesha S Jan 22 '18 at 17:34