Android endless scrolling with RecyclerView
This tutorial will illustrate how to implement infinite scrolling in Android, where the data should be load automatically as the user scrolls down
Filter by Category
Filter by Author
This tutorial will illustrate how to implement infinite scrolling in Android, where the data should be load automatically as the user scrolls down
Posted by Baraa Abuzaid
Example that goes through making a UML class diagram from simple problem statement
Posted by Baraa Abuzaid
This is a part of a blog series that will go through all you need to know about UML class Diagram to get up and running quickly
Posted by Baraa Abuzaid
This tutorial will illustrate how to implement infinite scrolling in Android, where the data should be load automatically as the user scrolls down
One of the most commonly used component in Android is the RecyclerView, there is almost no app that doesn’t contain some kind of list that needs to be displayed. Meanwhile, presenting an endless List (Infinite List) could be quite tricky. And in this context, there is two no! no! you would like to avoid when displaying online data on a list.
First, you don’t want to make a huge request call to the server, making your user wait infinitely. Second, you don’t want to clutter your UI with Next and previous button and make your App look like a web page from the 90’s.
In such a scenario implementing an endless scroll might be the ideal choice. Basically, before the user reaches the end of our recyclerView or a predefined threshold, we want to make a request call to the server and load new contents.
So initially we make a class the extends RecyclerView.OnScrollListener with abstract method onLoadMore() that would be overridden later to implement the request call to the server or to the database. Onscrolled() is a core method and will be called when the user scrolls our RecycledView, perhaps multiple time per second.
The method reset() is for resetting the member variable we are about to define.
public abstract class EndlessScrollEventListener extends RecyclerView.OnScrollListener {
private LinearLayoutManager mLinearLayoutManager;
public EndlessScrollEventListener(LinearLayoutManager linearLayoutManager) {
mLinearLayoutManager = linearLayoutManager;
}
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
}
public void reset(){};
public abstract void onLoadMore(int pageNum);
}
So the member variable of our EndlessScrollEventListener is as below
/** is number of items that we could have after our
* current scroll position before we start loading
more items */
private int visibleThreshold = 5;
/** to keep track of the page that we would like to
* retrieve from a server our database
* */
private int currentPage = 0;
/** total number of items that we retrieve lastly*/
private int previousTotalItemCount = 0;
/** indicating whether we are loading new dataset or not*/
private boolean loading = true;
/** the initial index of the page that'll start from */
private int startingPageIndex = 0;
/******* variables we could get from linearLayoutManager *******/
/** the total number of items that we currently have on our recyclerview and we
* get it from linearLayoutManager */
private int totalItemCount;
/** the position of last visible item in our view currently
* get it from linearLayoutManager */
private int lastVisibleItemPosition;
Moreover, let’s discuss how we could put all these together to get our intended result.
Basically, we have three major cases that we should address in our method onScrolled().
Firstly, if (totalItemCount < previousTotalItemCount)
that’s mean we should invalidate our list and rest back to our initial state.
Secondly, if we are loading we go and check whether
(totalItemCount > previousTotalItemCount) if true that means we finished loading a new dataset, then we:
– set loading to false
– set previousTotalItemCount to our new totalItemCount
The third case, we finished loading and
(lastVisibleItemPosition + visibleThreshold) > totalItemCount) that’s mean we have to load new contents as we reached the closest point to the bottom of our list.
Now, putting these cases together should be like
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
totalItemCount = mLinearLayoutManager.getItemCount();
lastVisibleItemPosition = mLinearLayoutManager.findLastVisibleItemPosition();
// first case
if (totalItemCount < previousTotalItemCount) {
this.currentPage = this.startingPageIndex;
this.previousTotalItemCount = totalItemCount;
if (totalItemCount == 0) { this.loading = true; }
}
// second case
if (loading && (totalItemCount > previousTotalItemCount)) {
loading = false;
previousTotalItemCount = totalItemCount;
}
// third case
if (!loading && (lastVisibleItemPosition + visibleThreshold) > totalItemCount) {
currentPage++;
onLoadMore(currentPage, recyclerView);
loading = true;
}
}
So putting it all together should be as below,
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
public abstract class EndlessScrollEventListener extends RecyclerView.OnScrollListener {
private LinearLayoutManager mLinearLayoutManager;
/** is number of items that we could have after our
* current scroll position before we start loading
more items */
private int visibleThreshold = 5;
/** to keep track of the page that we would like to
* retrieve from a server our database
* */
private int currentPage = 0;
/** total number of items that we retrieve lastly*/
private int previousTotalItemCount = 0;
/** indicating whether we are loading new dataset or not*/
private boolean loading = true;
/** the initial index of the page that'll start from */
private int startingPageIndex = 0;
/******* variables we could get from linearLayoutManager *******/
/** the total number of items that we currently have on our recyclerview and we
* get it from linearLayoutManager */
private int totalItemCount;
/** the position of last visible item in our view currently
* get it from linearLayoutManager */
private int lastVisibleItemPosition;
public EndlessScrollEventListener(LinearLayoutManager linearLayoutManager) {
mLinearLayoutManager = linearLayoutManager;
}
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
totalItemCount = mLinearLayoutManager.getItemCount();
lastVisibleItemPosition = mLinearLayoutManager.findLastVisibleItemPosition();
// first case
if (totalItemCount < previousTotalItemCount) {
this.currentPage = this.startingPageIndex;
this.previousTotalItemCount = totalItemCount;
if (totalItemCount == 0) { this.loading = true; }
}
// second case
if (loading && (totalItemCount > previousTotalItemCount)) {
loading = false;
previousTotalItemCount = totalItemCount;
}
// third case
if (!loading && (lastVisibleItemPosition + visibleThreshold) > totalItemCount) {
currentPage++;
onLoadMore(currentPage, recyclerView);
loading = true;
}
}
// should be called if we do filter(search) to our list
public void reset(){
this.currentPage = this.startingPageIndex;
this.previousTotalItemCount = 0;
this.loading = true;
}
// Define the place where we load the dataset
public abstract void onLoadMore(int pageNum, RecyclerView recyclerView);
}
In short, you’ll need to make a basic RecyclerView Adapter, and your activity or fragment should be like
public class MainActivity extends AppCompatActivity {
private RecyclerView recyclerView;
private MyRecyclerAdapter mAdapter;
private List<String> mList = new ArrayList<>();
private EndlessScrollEventListener endlessScrollEventListener;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
recyclerView = findViewById(R.id.recyclerView);
mAdapter = new MyRecyclerAdapter(this,mList);
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
recyclerView.setAdapter(mAdapter);
recyclerView.setLayoutManager(layoutManager);
endlessScrollEventListener = new EndlessScrollEventListener(layoutManager) {
@Override
public void onLoadMore(int pageNum, RecyclerView recyclerView) {
/*Todo: add your request call to load more data from server or database here */
}
};
recyclerView.addOnScrollListener(endlessScrollEventListener);
}
}
Feature Photo by NordWood
Tech industry is moving at a staggering pace. Gone the good old days when a release cycle takes year or more. And we enter a new era. The era of Apps and “rapid release cycle”....
Uber is a nice and features rich App, here in this tutorial we’ll implement a feature on it that is very useful. In particular, moving the map under the marker which is UBER...
Thank you for very clear way of implementing paging state. I think we should add if(dy < 0) return at the top of onScrolled()
you are welcome Aung,