How to Implement Paginate a query on android Fires

2019-04-02 21:46发布

This question already has an answer here:

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

2条回答
\"骚年 ilove
2楼-- · 2019-04-02 22:17

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

查看更多
你好瞎i
3楼-- · 2019-04-02 22:25

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
查看更多
登录 后发表回答