I have successfully implemented the Endless Scrolling using Recycler view. I am using this code and this works perfectly but except with the following case
Case 1: When the list has 2 items which are lesser then the screen size so its looks like the OnLoadMore calls again as it finds itself arriving to the end of the list
What I am doing: I am getting the list from 1 fragment and then send this list to the other fragment and in that fragment there is a RecyclerView with the onScroll listner here it is as follows :
recyclerView.addOnScrollListener(new EndlessRecyclerOnScrollListener(mLayoutManager) {
@Override
public void onLoadMore(int page, int totalItemsCount) {
// do something...
currentVisiblePosition = ((LinearLayoutManager) recyclerView.getLayoutManager()).findFirstCompletelyVisibleItemPosition();
pageNumber = pageNumber + 1;
CallingMyApi();
}
});
Confusions:
So i can guess that it is problem due to the less items in the list view How to control that please help me ??
Update 1: My Fragment Code
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mAdapter = new EnrollmentSearchAdapter(getActivity(), parentList);
rvSearchEnrollments.addOnScrollListener(new EndlessRecyclerOnScrollListener(mLayoutManager) {
@Override
public void onLoadMore(int page, int totalItemsCount) {
// do something...
if(parentList!=null && parentList.size()>3) { // just checking my own that 3 items should not be minimum to screen size , where as here it should be more flexible solution
currentVisiblePosition = ((LinearLayoutManager) rvSearchEnrollments.getLayoutManager()).findFirstCompletelyVisibleItemPosition();
pageNumber = pageNumber + 1;
SearchSundaySchoolParentsCouples searchSundaySchoolParentsCouples = new SearchSundaySchoolParentsCouples(keyword, 20, pageNumber, getActivity());
searchSundaySchoolParentsCouples.execute();
}
}
});
rvSearchEnrollments.addItemDecoration(new SimpleDividerItemDecoration(getActivity()));
rvSearchEnrollments.setAdapter(mAdapter);
}
mLinearLayoutManager = new LinearLayoutManager(this); recyclerView. setLayoutManager(mLinearLayoutManager); 3). On your Button onClick , do this to scroll to the bottom of your RecyclerView .
To help you build apps with lists, Android provides the RecyclerView . RecyclerView is designed to be very efficient, even with large lists, by reusing, or recycling, the views that have scrolled off the screen.
Use the EndlessRecyclerViewScrollListener OnScrollListener
subclass (it's from a popular Gist). You'll need to change a few things in order to get an endless Scrolling RecyclerView working when the items in the list are minimum then screen size.
Here's what you need to add to the EndlessRecyclerViewScrollListener class:
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState)
{
super.onScrollStateChanged(recyclerView, newState);
// Don't do any work until after the ScrollEvent has ended, so do the following check.
if (newState == RecyclerView.SCROLL_STATE_IDLE)
{
// supply a positive number to recyclerView.canScrollVertically(int direction) to check if scrolling down.
boolean canScrollDownMore = recyclerView.canScrollVertically(1);
// If recyclerView.canScrollVertically(1) returns false it means you're at the end of the list.
if (!canScrollDownMore)
{
//call the overridden onScrolled() method in our EndlessRecyclerViewScrollListener class.
// supply any positive number to the third argument to indicate that we've scrolled downward.
onScrolled(recyclerView, 0, 1);
}
}
}
Explanation: We need to implement the onScrollStateChanged()
method because onScrolled()
doesn't get called when at the end of a list, or at least it doesn't get called when the items in the list are minimum then screen size.
Here's the entire EndlessRecyclerViewScrollListener
class with the updates that you'll need:
public abstract class EndlessRecyclerViewScrollListener extends RecyclerView.OnScrollListener
{
// The minimum amount of items to have below your current scroll position
// before loading more.
private int visibleThreshold = 5;
// The current offset index of data you have loaded
private int currentPage = 0;
// The total number of items in the dataset after the last load
private int previousTotalItemCount = 0;
// True if we are still waiting for the last set of data to load.
private boolean loading = true;
// Sets the starting page index
private int startingPageIndex = 0;
private RecyclerView.LayoutManager layoutManager;
public void setLayoutManager(RecyclerView.LayoutManager layoutManager)
{
this.layoutManager = layoutManager;
}
public RecyclerView.LayoutManager getLayoutManager()
{
return layoutManager;
}
public EndlessRecyclerViewScrollListener(LinearLayoutManager layoutManager)
{
this.layoutManager = layoutManager;
}
public EndlessRecyclerViewScrollListener(GridLayoutManager layoutManager, int visibleThreshold)
{
this.layoutManager = layoutManager;
this.visibleThreshold = visibleThreshold * layoutManager.getSpanCount();
}
public EndlessRecyclerViewScrollListener(
StaggeredGridLayoutManager layoutManager,
int visibleThreshold)
{
this.layoutManager = layoutManager;
this.visibleThreshold = visibleThreshold * layoutManager.getSpanCount();
}
public int getLastVisibleItem(int[] lastVisibleItemPositions)
{
int maxSize = 0;
for (int i = 0; i < lastVisibleItemPositions.length; i++)
{
if (i == 0)
{
maxSize = lastVisibleItemPositions[i];
}
else if (lastVisibleItemPositions[i] > maxSize)
{
maxSize = lastVisibleItemPositions[i];
}
}
return maxSize;
}
// This happens many times a second during a scroll, so be wary of the code you place here.
// We are given a few useful parameters to help us work out if we need to load some more data,
// but first we check if we are waiting for the previous load to finish.
@Override
public void onScrolled(RecyclerView view, int dx, int dy)
{
if (dy < 1)
{
// don't do anything when scrolling up.
return;
}
int lastVisibleItemPosition = 0;
int totalItemCount = layoutManager.getItemCount();
if (layoutManager instanceof StaggeredGridLayoutManager)
{
int[] lastVisibleItemPositions = ((StaggeredGridLayoutManager) layoutManager).findLastVisibleItemPositions(null);
// get maximum element within the list
lastVisibleItemPosition = getLastVisibleItem(lastVisibleItemPositions);
}
else if (layoutManager instanceof GridLayoutManager)
{
lastVisibleItemPosition = ((GridLayoutManager) layoutManager).findLastVisibleItemPosition();
}
else if (layoutManager instanceof LinearLayoutManager)
{
lastVisibleItemPosition = ((LinearLayoutManager) layoutManager).findLastVisibleItemPosition();
}
// If the total item count is zero and the previous isn't, assume the
// list is invalidated and should be reset back to initial state
if (totalItemCount < previousTotalItemCount)
{
this.currentPage = this.startingPageIndex;
this.previousTotalItemCount = totalItemCount;
if (totalItemCount == 0)
{
this.loading = true;
}
}
// If it’s still loading, we check to see if the dataset count has
// changed, if so we conclude it has finished loading and update the current page
// number and total item count.
if (loading && (totalItemCount >= previousTotalItemCount))
{
loading = false;
previousTotalItemCount = totalItemCount;
}
// If it isn’t currently loading, we check to see if we have breached
// the visibleThreshold and need to reload more data.
// If we do need to reload some more data, we execute onLoadMore to fetch the data.
// threshold should reflect how many total columns there are too
if (!loading && (lastVisibleItemPosition + visibleThreshold) > totalItemCount)
{
currentPage++;
onLoadMore(currentPage, totalItemCount, view);
loading = true;
}
}
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState)
{
super.onScrollStateChanged(recyclerView, newState);
if (newState == RecyclerView.SCROLL_STATE_IDLE)
{
// supply a positive number to recyclerView.canScrollVertically(int direction) to check if scrolling down.
boolean canScrollDownMore = recyclerView.canScrollVertically(1);
// If recyclerView.canScrollVertically(1) returns false it means you're at the end of the list.
if (!canScrollDownMore)
{
onScrolled(recyclerView, 0, 1);
}
}
}
// Call this method whenever performing new searches on in onRefresh() if using SwipeRefresh
public void resetState()
{
this.currentPage = this.startingPageIndex;
this.previousTotalItemCount = 0;
this.loading = true;
}
// Defines the process for actually loading more data based on page
public abstract void onLoadMore(int page, int totalItemsCount, RecyclerView view);
}
Brief sample of usage: (more info here)
public class MainActivity extends Activity {
// Store a member variable for the listener
private EndlessRecyclerViewScrollListener scrollListener;
@Override
protected void onCreate(Bundle savedInstanceState) {
// Configure the RecyclerView
RecyclerView rvItems = (RecyclerView) findViewById(R.id.rvContacts);
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
rvItems.setLayoutManager(linearLayoutManager);
// Retain an instance so that you can call `resetState()` for fresh searches
scrollListener = new EndlessRecyclerViewScrollListener(linearLayoutManager) {
@Override
public void onLoadMore(int page, int totalItemsCount, RecyclerView view) {
// Triggered only when new data needs to be appended to the list
// Add whatever code is needed to append new items to the bottom of the list
loadNextDataFromApi(page);
}
};
// Adds the scroll listener to RecyclerView
rvItems.addOnScrollListener(scrollListener);
}
// Append the next page of data into the adapter
// This method probably sends out a network request and appends new data items to your adapter.
public void loadNextDataFromApi(int offset) {
// Send an API request to retrieve appropriate paginated data
// --> Send the request including an offset value (i.e `page`) as a query parameter.
// --> Deserialize and construct new model objects from the API response
// --> Append the new data objects to the existing set of items inside the array of items
// --> Notify the adapter of the new items made with `notifyItemRangeInserted()`
}
}
You may need to modify things a bit to get it working in your scenario, but the code provided is a GREAT starting point.
You can do your load more task something like this in recyclerview if list are minimum then screen size
@Override
public void onBindViewHolder(DataObjectHolder holder, int position) {
holder.label.setText(mDataset.get(position).getmText1());
holder.dateTime.setText(mDataset.get(position).getmText2());
if (position == this.getItemCount() - 1 && !loading){
// do your load more task here
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With