Firebase android pagination
Below is the code I'm using for pagination which shows the latest node first.
public void getImages() {
Query imagesQuery = FirebaseDatabase.getInstance().getReference().child("englishDps").child(mChildName).orderByKey().limitToLast(21);
ChildEventListener childEventListener = new ChildEventListener() {
@Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
Image image = dataSnapshot.getValue(Image.class);
image.setNodeKey(dataSnapshot.getKey());
mTempImages.add(image);
if (mTempImages.size() == 21) {
mLastKey = mTempImages.get(0).getNodeKey();
Collections.reverse(mTempImages);
mTempImages.remove(mTempImages.size() - 1);
mImages.addAll(mTempImages);
setAdapter();
}
}
@Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
}
@Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
}
@Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
@Override
public void onCancelled(DatabaseError databaseError) {
if (isAdded()) {
Toast.makeText(getActivity(), "Problem loading more images...", Toast.LENGTH_LONG).show();
}
}
};
imagesQuery.addChildEventListener(childEventListener);
}
@Override
public void getMoreImages() {
if (!mGettingMoreImages) {
mGettingMoreImages = true;
Query imagesQuery = FirebaseDatabase.getInstance().getReference("englishDps").child(mChildName).orderByKey().endAt(mLastKey).limitToLast(21);
ChildEventListener childEventListener = new ChildEventListener() {
@Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
Image image = dataSnapshot.getValue(Image.class);
image.setNodeKey(dataSnapshot.getKey());
mMoreImages.add(image);
if (mMoreImages.size() == 21) {
mLastKey = mMoreImages.get(0).getNodeKey();
Collections.reverse(mMoreImages);
mMoreImages.remove(mMoreImages.size() - 1);
mImages.addAll(mMoreImages);
mMoreImages.clear();
mGettingMoreImages = false;
mImagesAdapter.notifyDataSetChanged();
return;
}
if (mLastKey.equalsIgnoreCase(image.getNodeKey())) {
Collections.reverse(mMoreImages);
mImages.addAll(mMoreImages);
mMoreImages.clear();
mGettingMoreImages = false;
mImagesAdapter.onNoMoreImages();
;
mImagesAdapter.notifyDataSetChanged();
}
}
@Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
}
@Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
}
@Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
@Override
public void onCancelled(DatabaseError databaseError) {
if (isAdded()) {
Toast.makeText(getActivity(), "Problem loading more images...", Toast.LENGTH_LONG).show();
}
}
};
imagesQuery.addChildEventListener(childEventListener);
}
}
Pagination in Firebase realtime database
FirebaseDatabase.getInstance(firebaseApp)
.getReference("resources")
.child(FSeason.key)
.orderByKey()
.startAt(id)
.limit(size)
Here, startAt(...)
will set the cursor in your database. The order of these data is defined by your orderByKey()
function which orders your data alphabetically. Moreover, the limit(...)
function defines how many data to retrieve per query.
Here's the official documentation on startAt(...):
Create a query constrained to only return child nodes with a value
greater than or equal to the given value, using the given orderBy
directive or priority as default.
The id
in startAt(id)
represents the id of the last retrieved document. So, every time you parse the results from your query, store the last element's id and use that for the next query.
Pagination in endless recycler view with firebase
To recognize that we have reached end of RecyclerView
you can use this class EndlessRecyclerOnScrollListener.java
To load more next question, you should define one more field in Question class
like number
public class Question {
private int number; // it must unique and auto increase when you add new question
...
}
Then when you load questions from FireBase
you can do like
public class MainActivity extends AppCompatActivity {
private static final int TOTAL_ITEM_EACH_LOAD = 10;
private DatabaseReference mDatabase;
final List<Question> questionList = new ArrayList<>();
private int currentPage = 0;
private RecyclerView recyclerView;
private RecyclerViewAdapter mAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
...
// init and set layout manager for your RecyclerView
...
mAdapter = new RecyclerViewAdapter(questionList);
recyclerView.setAdapter(mAdapter);
recyclerView.setOnScrollListener(new EndlessRecyclerOnScrollListener(mLayoutManager) {
@Override
public void onLoadMore(int current_page) { // when we have reached end of RecyclerView this event fired
loadMoreData();
}
});
loadData(); // load data here for first time launch app
}
private void loadData() {
// example
// at first load : currentPage = 0 -> we startAt(0 * 10 = 0)
// at second load (first loadmore) : currentPage = 1 -> we startAt(1 * 10 = 10)
mDatabase.child("questions")
.limitToFirst(TOTAL_ITEM_EACH_LOAD)
.startAt(currentPage*TOTAL_ITEM_EACH_LOAD)
.orderByChild("number")
.addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
if(!dataSnapshot.hasChildren()){
Toast.makeText(MainActivity.this, "No more questions", Toast.LENGTH_SHORT).show();
currentPage--;
}
for (DataSnapshot data : dataSnapshot.getChildren()) {
Question question = data.getValue(Question.class);
questionList.add(question);
mAdapter.notifyDataSetChanged();
}
}
@Override public void onCancelled(DatabaseError databaseError) {}});
}
private void loadMoreData(){
currentPage++;
loadData();
}
}
Here is my DEMO project
firebase android pagination with recyclerview
You'd use endAt()
, since you want the last item to be returned to be the "oldest" one that you got before.
DatabaseReference jokesRef = FirebaseDatabase.getInstance().getReference().child("hindi-jokes");
Query jokesQuery = jokesRef.orderByKey().endAt(oldestKeyYouveSeen).limitToLast(20);
The oldestKeyYouveSeen
is known as the anchor. You need to track this yourself in your code: setting it to the key of the oldest item that you'd you've seen.
Note that it will be both in the first query and in the second, so you'll have to explicitly exclude it once in your code.
Related Topics
Android Viewmodel Additional Arguments
Disable Orange Outline Highlight on Focus
How to Get a Dialog Style Activity Window to Fill the Screen
How to Measure Height, Width and Distance of Object Using Camera
Recyclerview Changing Items During Scroll
How to Display a List of Images in a Listview in Android
Can't Include C++ Headers Like Vector in Android Ndk
How to Add New Column to Android SQLite Database
Android + Pair Devices via Bluetooth Programmatically
Android: Remove All the Previous Activities from the Back Stack
Keep a Service Running Even When Phone Is Asleep
How to Get Hosting Activity from a View
Disable Edittext Blinking Cursor
How to Represent a "Many to Many" Relation with Android Room When Column Names Are Same
Expandablelistview - Hide Indicator for Groups with No Children
Remove Image from Cache in Glide Library
How to Programmatically Set the Background Color Gradient on a Custom Title Bar
Publish an Android Library to Maven with Aar and Sources Jar