I want to implement an endless RecyclerView but so far all the implementations and tutorials I have come across describe loading data off a server then loading it or dynamically adding elements using a loop.
In my case, I already have a large ArrayList containing the data I want to display in the RecyclerView.
What I need is to say, display the first 10 items of the array, and on loading more, display the next batch of 10.
This could achieve your goal.
public abstract class EndlessRecyclerOnScrollListener extends RecyclerView.OnScrollListener {
public static String TAG = EndlessRecyclerOnScrollListener.class.getSimpleName();
private int previousTotal = 0; // The total number of items in the dataset after the last load
private boolean loading = true; // True if we are still waiting for the last set of data to load.
private int visibleThreshold = 5; // The minimum amount of items to have below your current scroll position before loading more.
int firstVisibleItem, visibleItemCount, totalItemCount;
private int current_page = 1;
private LinearLayoutManager mLinearLayoutManager;
public EndlessRecyclerOnScrollListener(LinearLayoutManager linearLayoutManager) {
this.mLinearLayoutManager = linearLayoutManager;
}
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
visibleItemCount = recyclerView.getChildCount();
totalItemCount = mLinearLayoutManager.getItemCount();
firstVisibleItem = mLinearLayoutManager.findFirstVisibleItemPosition();
if (loading) {
if (totalItemCount > previousTotal) {
loading = false;
previousTotal = totalItemCount;
}
}
if (!loading && (totalItemCount - visibleItemCount)
<= (firstVisibleItem + visibleThreshold)) {
// End has been reached
// Do something
current_page++;
onLoadMore(current_page);
loading = true;
}
}
public abstract void onLoadMore(int current_page);
}
And sample activity
public class SampleActivity extends ActionBarActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sample);
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.list);
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(linearLayoutManager);
recyclerView.setOnScrollListener(new EndlessRecyclerOnScrollListener(linearLayoutManager) {
#Override
public void onLoadMore(int current_page) {
// do something...
}
});
}
}
Edit: See here: Endless Scrolling with AdapterViews
You can use this Endless Adapter
It is generic, you give it (You model, Recycler.ViewHolder)
You can set the adapter either show loading or not.
Have Listeners to check when loading finished, and when loading starts.
You can check also the sample for more info
Try using:
recyclerView.addOnScrollListener (recyclerViewOnScrollListener);
private RecyclerView.OnScrollListener recyclerViewOnScrollListener = new RecyclerView.OnScrollListener () {
private final String LOG_TAG = "PAGINATION_";
boolean isIdle;
#Override
public void onScrollStateChanged (RecyclerView recyclerView, int newState) {
try {
super.onScrollStateChanged (recyclerView, newState);
isIdle = (newState == RecyclerView.SCROLL_STATE_IDLE);
}
catch (Exception e) {
e.printStackTrace ();
}
}
#Override
public void onScrolled (RecyclerView recyclerView, int dx, int dy) {
firstVisibleItemPosition = layoutManager.findFirstVisibleItemPosition ();
super.onScrolled (recyclerView, dx, dy);
if (!isIdle dy > 0) {
int totalItems = yourList.size()();
totalItemCount = layoutManager.getItemCount ();
visibleItemCount = layoutManager.getChildCount ();
Log.i (LOG_TAG, "Max: " + totalItems + ", Total: " + totalItemCount + ", Previous Total: " + previousTotal + ", Visible: " + visibleItemCount + ", First: " + firstVisibleItemPosition);
if (isLoading) {
if (totalItemCount != previousTotal) {
isLoading = false;
previousTotal = totalItemCount;
}
}
isLastPage = (totalItemCount >= totalItems);
Log.i (LOG_TAG, "DETAILS: currentPage: " + currentPage + ", isLoading: " + isLoading + ", isLast: " + isLastPage);
if (!isLoading && !isLastPage) {
if ((visibleItemCount + firstVisibleItemPosition) >= totalItemCount && firstVisibleItemPosition >= 0 && totalItems >= (currentPage * PAGE_LIMIT) && totalItems > totalItemCount) {
if (totalItems > (currentPage * PAGE_LIMIT)) {
currentPage = (totalItemCount / PAGE_LIMIT) + 1;
isLoading = true;
//load more data using currentPage and PAGE_LIMIT
}
}
}
}
previousTotal = totalItemCount;
}
catch (Exception e) {
e.printStackTrace ();
}
}
}
}
};
try using this class it help me alot :
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;
RecyclerView.LayoutManager mLayoutManager;
public EndlessRecyclerViewScrollListener(LinearLayoutManager layoutManager) {
this.mLayoutManager = layoutManager;
}
public EndlessRecyclerViewScrollListener(GridLayoutManager layoutManager) {
this.mLayoutManager = layoutManager;
visibleThreshold = visibleThreshold * layoutManager.getSpanCount();
}
public EndlessRecyclerViewScrollListener(StaggeredGridLayoutManager layoutManager) {
this.mLayoutManager = layoutManager;
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) {
int lastVisibleItemPosition = 0;
int totalItemCount = mLayoutManager.getItemCount();
if (mLayoutManager instanceof StaggeredGridLayoutManager) {
int[] lastVisibleItemPositions = ((StaggeredGridLayoutManager) mLayoutManager).findLastVisibleItemPositions(null);
// get maximum element within the list
lastVisibleItemPosition = getLastVisibleItem(lastVisibleItemPositions);
} else if (mLayoutManager instanceof GridLayoutManager) {
lastVisibleItemPosition = ((GridLayoutManager) mLayoutManager).findLastVisibleItemPosition();
} else if (mLayoutManager instanceof LinearLayoutManager) {
lastVisibleItemPosition = ((LinearLayoutManager) mLayoutManager).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;
}
}
// Call this method whenever performing new searches
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);
}
reference :
https://gist.github.com/nesquena/d09dc68ff07e845cc622
https://guides.codepath.com/android/Endless-Scrolling-with-AdapterViews-and-RecyclerView
Related
I follow this code to add endlessscroll for RecyclerView, it's work but when i scroll to the end, data load done and the list back up to top over and over again, scroll to the end, data load done and back up to top of the list. How to fix it? I really don't understand why, please help me, thank you very much.
Here, this is my code:
public abstract class EndlessOnScrollListener 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;
RecyclerView.LayoutManager mLayoutManager;
public EndlessOnScrollListener(LinearLayoutManager layoutManager) {
this.mLayoutManager = layoutManager;
}
public EndlessOnScrollListener(GridLayoutManager layoutManager) {
this.mLayoutManager = layoutManager;
visibleThreshold = visibleThreshold * layoutManager.getSpanCount();
}
public EndlessOnScrollListener(StaggeredGridLayoutManager layoutManager) {
this.mLayoutManager = layoutManager;
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) {
int lastVisibleItemPosition = 0;
int totalItemCount = mLayoutManager.getItemCount();
if (mLayoutManager instanceof StaggeredGridLayoutManager) {
int[] lastVisibleItemPositions = ((StaggeredGridLayoutManager) mLayoutManager).findLastVisibleItemPositions(null);
// get maximum element within the list
lastVisibleItemPosition = getLastVisibleItem(lastVisibleItemPositions);
} else if (mLayoutManager instanceof LinearLayoutManager) {
lastVisibleItemPosition = ((LinearLayoutManager) mLayoutManager).findLastVisibleItemPosition();
} else if (mLayoutManager instanceof GridLayoutManager) {
lastVisibleItemPosition = ((GridLayoutManager) mLayoutManager).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);
loading = true;
}
}
// Defines the process for actually loading more data based on page
public abstract void onLoadMore(int page, int totalItemsCount);
}
private void setUpRecyclerViewVideo() {
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(MainActivity.this, LinearLayoutManager.VERTICAL, false);
rvVideo.setLayoutManager(linearLayoutManager);
rvVideo.setHasFixedSize(true);
rvVideo.setItemAnimator(new DefaultItemAnimator());
rvVideo.setAdapter(adapterVideo);
swipe_container.setRefreshing(false);
adapterVideo.notifyDataSetChanged();
if (isLoadMore){
rvVideo.addOnScrollListener(new EndlessOnScrollListener(linearLayoutManager) {
#Override
public void onLoadMore(int page, int totalItemsCount) {
fetchVideoDataFromServer("https://afternoon-beyond-44158.herokuapp.com/all/" + Constants.PAGE_SIZE_5 + "/" + totalItemsCount);
}
});
}
It is example for EndlessOnScrollView .
Pagination using retrofit to fetch next 10 items from API on scrolling in android
instead,
for pagination if you are using simple listview with BaseAdapter,
then you may follow below code.
Use 2 arrayList for paginataion.
one is to load all listview items(allDataList), and one is to set 10 items in adapter(paginationList).
first load all data in allDataList by using retrofit.
public static int itemsCount = 10;
//i need pagination of 10 records, so here i passed 10, you may increase this no. here as your requirement.
ArrayList<User_pojo> allDataList, paginationList;
Adapter_UserList adapter;
ListView listViewUser;
View footerView;
LayoutInflater layoutInflater;
int lastItem,preLast;
Context context;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
context = this;
listViewUser = (ListView) findViewById(R.id.listViewUser);
allDataList = new ArrayList<>();
paginationList = new ArrayList<>();
layoutInflater = LayoutInflater.from(context);
footerView = layoutInflater.inflate(R.layout.load_more_view, null);
listViewUser.addFooterView(footerView);
Call_api();
listViewUser.setOnScrollListener(new AbsListView.OnScrollListener() {
#Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
}
#Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
lastItem = (firstVisibleItem + visibleItemCount);
if (lastItem == totalItemCount) {
if (preLast != lastItem) {
//to avoid multiple calls for last item
preLast = lastItem;
footerView.findViewById(R.id.progress_bar).setVisibility(View.VISIBLE);
footerView.postDelayed(new Runnable() {
#Override
public void run() {
itemsCount += 10;
LoadMoreList();
listViewUser.setSelection(lastItem - 1); //to display more loaded records # current displayed position.
}
}, 1500);
}
}
}
});
}
#Override
public void onStart() {
super.onStart();
LoadMoreList();
}
public interface AppService{
#FormUrlEncoded
#POST("getUserList")
Call<User_pojo> getUserList(#FieldMap(encoded = true) Map<String, String> map);
}
void Call_api() {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://your_api_url_here.com/")
.addConverterFactory(GsonConverterFactory.create())
.build();
Call<User_pojo> call = retrofit.create(AppService.class).getUserList(getUserMap());
call.enqueue(new Callback<User_pojo>() {
#Override
public void onResponse(Call<User_pojo> call, Response<User_pojo> response) {
Log.e("Response", new Gson().toJson(response.body()));
if (response.body().getResponse().equalsIgnoreCase("true")) {
allDataList = response.body().getData();
Log.e("size", allDataList.size() + "");
LoadMoreList();
}
}
#Override
public void onFailure(Call<User_pojo> call, Throwable t) {
t.printStackTrace();
t.getMessage();
Log.e("Failed", t.getMessage());
}
});
}
private void LoadMoreList() {
try {
Log.e("size", String.valueOf(allDataList.size()));
if (allDataList.size() >= itemsCount) {
paginationList.clear();
for (int i = 0; i < itemsCount; i++) {
paginationList.add(allDataList.get(i));
}
Log.e("paginationList_Size", String.valueOf(paginationList.size()));
adapter = new Adapter_UserList(context, paginationList);
} else {
adapter = new Adapter_UserList(context, allDataList);
listViewUser.removeFooterView(footerView); // loaded all list then simply remove footerView.
}
if (footerView != null)
footerView.findViewById(R.id.progress_bar).setVisibility(View.INVISIBLE);
listViewUser.setAdapter(adapter);
} catch (Exception ignored) {
}
}
private Map<String, String> getUserMap() {
Map<String, String> map = new HashMap<>();
map.put("uid", "001");
map.put("token", "5526");
Log.e("logs", map.toString());
return map;
}
hope this help.
In your recycleview ScrollListener
private static final int PAGE_START = 0;
private boolean isLoading = false;
private boolean isLastPage = false;
private int TOTAL_PAGES = 3; //your total page
private int currentPage = PAGE_START;
rv.addOnScrollListener(new PaginationScrollListener(linearLayoutManager) {
#Override
protected void loadMoreItems() {
isLoading = true;
currentPage += 1;
loadApi(currentPage); //pass page number as parameter in your api calls
}
#Override
public int getTotalPageCount() {
return TOTAL_PAGES;
}
#Override
public boolean isLastPage() {
return isLastPage;
}
#Override
public boolean isLoading() {
return isLoading;
}
});
}
more details refer Pagination Android RecyclerView
Use below EndlessRecyclerViewScrollListener class.
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;
RecyclerView.LayoutManager mLayoutManager;
public EndlessRecyclerViewScrollListener(LinearLayoutManager layoutManager) {
this.mLayoutManager = layoutManager;
}
public EndlessRecyclerViewScrollListener(GridLayoutManager layoutManager) {
this.mLayoutManager = layoutManager;
visibleThreshold = visibleThreshold * layoutManager.getSpanCount();
}
public EndlessRecyclerViewScrollListener(StaggeredGridLayoutManager layoutManager) {
this.mLayoutManager = layoutManager;
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) {
int lastVisibleItemPosition = 0;
int totalItemCount = mLayoutManager.getItemCount();
if (mLayoutManager instanceof StaggeredGridLayoutManager) {
int[] lastVisibleItemPositions = ((StaggeredGridLayoutManager) mLayoutManager).findLastVisibleItemPositions(null);
// get maximum element within the list
lastVisibleItemPosition = getLastVisibleItem(lastVisibleItemPositions);
} else if (mLayoutManager instanceof GridLayoutManager) {
lastVisibleItemPosition = ((GridLayoutManager) mLayoutManager).findLastVisibleItemPosition();
} else if (mLayoutManager instanceof LinearLayoutManager) {
lastVisibleItemPosition = ((LinearLayoutManager) mLayoutManager).findLastVisibleItemPosition();
if (((LinearLayoutManager) mLayoutManager).findFirstCompletelyVisibleItemPosition() == 0) {
doPullToRefresh();
}
}
// 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;
}
}
// Call this method whenever performing new searches
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);
public abstract void doPullToRefresh();
}
Initialise recycler view and add scroll listener to the recycler view as:
scrollListener = new EndlessRecyclerViewScrollListener(llm) {
#Override
public void onLoadMore(int page, int totalItemsCount, RecyclerView view) {
fetchNextTenRecords(page);
}
#Override
public void doPullToRefresh() {
swipeRefreshLayout.setEnabled(true);
}
};
Using RecyclerView.OnScrollListener and RecyclerView.LayoutManager you can find index of the last visible item. If the index equals to the total items count - 1 you can consider it as the end of the list and load the next page.
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
if (dy > 0) //check for scroll down
{
int totalItemCount = layoutManager.getItemCount();
int lastVisibleItemPosition = layoutManager.findLastVisibleItemPosition();
if (!loading && lastVisibleItemPosition == totalItemCount - 1) {
loading = true;
currentPage = currentPage + 1;
if (!dynamicPages.equalsIgnoreCase("")) {
loadMoreData(currentPage);
}
}
}
}
});
I have a user feed where user's posts will be displayed if the current user is following them, at the moment I have the loadMoreListener working fine in regards to it loading the next batch of images when they get to the bottom of the RecyclerView. But, when I reach the last item (the feeds only shows 50 posts) in the List it'll attempt to load more and cause an OutOfMemoryException. I've restricted the size of the list in the adapter, but at the minute I can't seem to work out when the user has hit the very bottom to stop the progress from displaying and to stop the OnLoadMoreListener from triggering. This is what I have tried so far:
Adapter Constructor:
public RecyclerViewAdapterAllFeeds(Context context,
final ArrayList<AllFeedsDataModel> previousPostsList, final boolean profile, RecyclerView recyclerView, final ProgressBar progressBar) {
this.context = context;
this.previousPostsList = previousPostsList;
this.profile = profile;
if(recyclerView.getLayoutManager() instanceof LinearLayoutManager){
final LinearLayoutManager linearLayoutManager = (LinearLayoutManager)recyclerView.getLayoutManager();
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
progressBar.setVisibility(View.VISIBLE);
if (getItemCount() > LOADED_POSTS - 2) {
totalItemCount = getItemCount();
// total_posts = getItemCount();
lastVisibleItem = linearLayoutManager.findLastVisibleItemPosition();
if (lastVisibleItem <= TOTAL_POSTS) {
if (!loading && totalItemCount <= (lastVisibleItem)) {
if (onLoadMoreListener != null) {
onLoadMoreListener.onLoadMore();
}
loading = true;
}
}
}
}
});
}
}
onLoadMoreListener
adapter = new RecyclerViewAdapterAllFeeds(getActivity(), latestUpdatesList, false, recyclerView, progressBar);
recyclerView.setAdapter(adapter);// set adapter on recyclerview
adapter.setOnLoadMoreListener(new RecyclerViewAdapterAllFeeds.OnLoadMoreListener() {
#Override
public void onLoadMore() {
refreshCount++;
populateRecyclerView(true, refreshCount);
adapter.update(updatesList);
adapter.setLoaded();
System.out.println("load");
}
});
adapter.notifyDataSetChanged();// Notify the adapter
progressBar.setIndeterminate(false);
progressBar.setVisibility(View.INVISIBLE);
My question is how can I stop it loading if the total posts is less than that of the restrictions or to know when the final item is visible?
First create EndlessRecyclerViewScrollListener.java:
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.StaggeredGridLayoutManager;
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;
RecyclerView.LayoutManager mLayoutManager;
public EndlessRecyclerViewScrollListener(LinearLayoutManager layoutManager) {
this.mLayoutManager = layoutManager;
}
public EndlessRecyclerViewScrollListener(GridLayoutManager layoutManager) {
this.mLayoutManager = layoutManager;
visibleThreshold = visibleThreshold * layoutManager.getSpanCount();
}
public EndlessRecyclerViewScrollListener(StaggeredGridLayoutManager layoutManager) {
this.mLayoutManager = layoutManager;
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) {
int lastVisibleItemPosition = 0;
int totalItemCount = mLayoutManager.getItemCount();
if (mLayoutManager instanceof StaggeredGridLayoutManager) {
int[] lastVisibleItemPositions = ((StaggeredGridLayoutManager) mLayoutManager).findLastVisibleItemPositions(null);
// get maximum element within the list
lastVisibleItemPosition = getLastVisibleItem(lastVisibleItemPositions);
} else if (mLayoutManager instanceof LinearLayoutManager) {
lastVisibleItemPosition = ((LinearLayoutManager) mLayoutManager).findLastVisibleItemPosition();
} else if (mLayoutManager instanceof GridLayoutManager) {
lastVisibleItemPosition = ((GridLayoutManager) mLayoutManager).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);
loading = true;
}
}
// Defines the process for actually loading more data based on page
public abstract void onLoadMore(int page, int totalItemsCount);
}
And then implement in this way:
recyclerView.addOnScrollListener(new EndlessRecyclerViewScrollListener(recyclerView.getLayoutManager()) {
#Override
public void onLoadMore(int page, int totalItemsCount) {
//TODO Add logic for load more posts or show message if posts is ended.
}
});
Check out the code which I use for endless scroll:
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
// if (BuildConfig.DEBUG)
// Log.d(TAG, "onScrolled: [x, y]=[" + dx + ", " + dy + "], count=[" + recyclerView.getLayoutManager().getChildCount() + ", " + recyclerView.getLayoutManager().getItemCount() + ", " + ((LinearLayoutManager) recyclerView.getLayoutManager()).findFirstVisibleItemPosition() + "]");
if (hasMoreRequest) {
if (dy > 0) { //check for scroll down
checkForMoreLoad();
}
}
}
});
private void checkForMoreLoad() {
final Handler handler = new Handler();
Runnable checkForMoreData = new Runnable() {
#Override
public void run() {
if (null != recyclerView) {
int visibleItemCount = recyclerView.getLayoutManager().getChildCount();
int totalItemCount = recyclerView.getLayoutManager().getItemCount();
int pastVisibleItems = ((LinearLayoutManager) recyclerView.getLayoutManager()).findFirstVisibleItemPosition();
onScrollToLoad(visibleItemCount, pastVisibleItems, totalItemCount);
}
}
};
handler.postDelayed(checkForMoreData, 100);
}
private void onScrollToLoad(int visibleItemCount, int pastVisibleItems, int totalItemCount) {
if ((visibleItemCount + pastVisibleItems) + 4 >= totalItemCount && hasMoreRequest) {
if (BuildConfig.DEBUG)
Log.d(TAG, "onScroll lastInScreen - so load more");
startNetworkCall(page + 1);
}
}
And after data from API, if there is more data after that I will again call checkForMoreLoad().
The line which has (visibleItemCount + pastVisibleItems) + 4 in onScrollToLoad() has 4 in it. It is for starting API before hand of reaching end of the scroll.
I have implemented pagination using EndlessRecyclerOnScrollListener. At a particular scenario I have to reset the page number, so i have created resetValues() method. But I don't know how to call this method from activity class.
public abstract class EndlessRecyclerOnScrollListener extends RecyclerView.OnScrollListener {
public static String TAG = EndlessRecyclerOnScrollListener.class.getSimpleName();
private int previousTotal = 0; // The total number of items in the dataset after the last load
private boolean loading = true; // True if we are still waiting for the last set of data to load.
private int visibleThreshold = 0; // The minimum amount of items to have below your current scroll position before loading more.
int firstVisibleItem, visibleItemCount, totalItemCount;
private int current_page = 1;
private LinearLayoutManager mLinearLayoutManager;
public EndlessRecyclerOnScrollListener(LinearLayoutManager linearLayoutManager,boolean isfromversion) {
this.mLinearLayoutManager = linearLayoutManager;
Log.e("isversionendless",isfromversion+"");
if(isfromversion)
{
resetValues();
}
}
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
visibleItemCount = recyclerView.getChildCount();
totalItemCount = mLinearLayoutManager.getItemCount();
firstVisibleItem = mLinearLayoutManager.findFirstVisibleItemPosition();
if (loading) {
if (totalItemCount > previousTotal) {
loading = false;
previousTotal = totalItemCount;
}
}
if (!loading && (totalItemCount - visibleItemCount)
<= (firstVisibleItem + visibleThreshold)) {
// End has been reached
// Do something
current_page++;
onLoadMore(current_page);
loading = true;
}
}
public void resetValues(){
previousTotal = 0;
loading = true;
visibleThreshold = 1;
firstVisibleItem = 0;
visibleItemCount = 0;
totalItemCount = 0;
}
public abstract void onLoadMore(int current_page);
}
EndlessRecyclerOnScrollListener scrollListener=new EndlessRecyclerOnScrollListener(
mGridLayoutManager) {
#Override
public void onLoadMore(int current_page) {
// do somthing...
loadMoreData(current_page);
}
};
recyclerView.setOnScrollListener(scrollListener);
when you want to reset values then just simply call method as below.
scrollListener.resetValues();
This is how I am setting up recyclerview.
mRecyclerViewRides = (RecyclerView) findViewById(R.id.recyclerViewRides);
// use this setting to improve performance if you know that changes
// in content do not change the layout size of the RecyclerView
mRecyclerViewRides.setHasFixedSize(true);
// use a linear layout manager
mLinearLayoutManager = new LinearLayoutManager(getApplicationContext());
mRecyclerViewRides.setLayoutManager(mLinearLayoutManager);
mRideListAdapter = new FindRideListAdapter(getApplicationContext(), mRecyclerViewRides, mRideDetailArrayList, mImageOptions, mImageLoader, this);
mRecyclerViewRides.setAdapter(mRideListAdapter);
mRecyclerViewRides.addOnScrollListener(new EndlessRecyclerOnScrollListener(mLinearLayoutManager) {
#Override
public void onLoadMore(int current_page) {
Log.e(TAG,"Scroll Count ==> "+(++mIntScrollCount));
if(!flagFirstLoad) {
mOffset = mOffset + mLimit;
getRideList(mOffset, mLimit);
}
}
});
This is the code for endless recycler view scroll listner.
public abstract class EndlessRecyclerOnScrollListener extends RecyclerView.OnScrollListener {
public static String TAG = EndlessRecyclerOnScrollListener.class.getSimpleName();
private int previousTotal = 0; // The total number of items in the dataset after the last load
private boolean loading = true; // True if we are still waiting for the last set of data to load.
private int visibleThreshold = 1; // The minimum amount of items to have below your current scroll position before loading more.
int firstVisibleItem, visibleItemCount, totalItemCount;
private int current_page = 1;
private LinearLayoutManager mLinearLayoutManager;
public EndlessRecyclerOnScrollListener(LinearLayoutManager linearLayoutManager) {
this.mLinearLayoutManager = linearLayoutManager;
}
/**
* function to reset values of the properties of this class to initial
*/
public void resetValues(){
previousTotal = 0;
loading = true;
visibleThreshold = 1;
firstVisibleItem = 0;
visibleItemCount = 0;
totalItemCount = 0;
}
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
visibleItemCount = recyclerView.getChildCount();
totalItemCount = mLinearLayoutManager.getItemCount();
firstVisibleItem = mLinearLayoutManager.findFirstVisibleItemPosition();
if (loading) {
if (totalItemCount > previousTotal) {
loading = false;
previousTotal = totalItemCount;
}
}
if (!loading && (totalItemCount - visibleItemCount)
<= (firstVisibleItem + visibleThreshold)) {
// End has been reached
// Do something
current_page++;
onLoadMore(current_page);
loading = true;
}
}
public abstract void onLoadMore(int current_page);}
So now whenever i scroll to bottom of the list onLoadMore() gets called twice and even intialy when i call getRideList() for the first time onScroll is getting invoked. I don't understand why?
Updated my support library and its working fine now.