I have a RecyclerView,I want it to be SwipeRefreshLayout when pull from top,so I can get the latest 20 item and show it at RecyclerView.At the same time,when reach the 20th item at the bottom,then fetch another 20th item from the database.
Therefore,I get the last item like below,so I can fetch the next 20th item.
//for endless scroll
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
visibleItemCount = recyclerView.getChildCount();
totalItemCount = mLayoutManager.getItemCount();
firstVisibleItem = mLayoutManager.findFirstVisibleItemPosition();
if (loading) {
if (totalItemCount > previousTotal) {
loading = false;
previousTotal = totalItemCount;
}
}
if (!loading && (totalItemCount - visibleItemCount)
<= (firstVisibleItem + visibleThreshold)) {
// End has been reached
Log.i("Yaeye!", "end called");
fetchPost(feedItems.get(feedItems.size()-1).getId());
//This function is fetch the next 20th item from database
// Do something
loading = true;
}
}
});
}
This is alright when it reach the bottom of the Recycleview,but the problem is when now is the top(1st item in RecyclerView),I pull down,suppose it fetch the new item,but it crashed.This is the error:
java.lang.ArrayIndexOutOfBoundsException: length=27; index=-1
Here is my code: for the SwipeRefreshLayout to fetch latest 20th item in database
// show loader and fetch messages
swipeRefreshLayout.post(
new Runnable() {
#Override
public void run() {
clear();
fetchIntialPost(); // this one,fetch the latest item
}
}
);
So I know that it cause by,when at the 1st item,it also consider the end of the RecyclerView,so it call fetchPost(feedItems.get(feedItems.size()-1).getId()); this function instead of this function fetchIntialPost();
So now my question is,when at the top(1st item),call fetchIntialPost(); when pull the SwipeRefreshLayout down?and the last item,just call fetchPost(feedItems.get(feedItems.size()-1).getId()); .
Thanks
I solved it by checking the value of feedItems.size()-1 before execute this line of code fetchPost(feedItems.get(feedItems.size()-1).getId());
Here is my working code :
//top and bottom also consider end of the list
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
visibleItemCount = recyclerView.getChildCount();
totalItemCount = mLayoutManager.getItemCount();
firstVisibleItem = mLayoutManager.findFirstVisibleItemPosition();
lastVisibleItem = mLayoutManager.findLastVisibleItemPosition();
if (loading) {
if (totalItemCount > previousTotal) {
loading = false;
previousTotal = totalItemCount;
}
}
if (!loading && (totalItemCount - visibleItemCount)
<= (firstVisibleItem + visibleThreshold)) {
// End has been reached
//top and bottom also consider end of the list
Log.i("Yaeye!", "end called");
if(feedItems.size() - 1 > 0) {
//when pull down SwipeRefreshLayout,feedItems.size = -1
//so if greater than 0,means is bottom of the list
// Do something
fetchPost(feedItems.get(feedItems.size() - 1).getId());
loading = true;
}else{
//here is the top of the list
}
}
}
});
Can you try this?
lastVisibleItem = mLayoutManager.findLastVisibleItemPosition();
if (!loading && lastVisibleItem == (totalItemCount - 1)) {
// End has been reached
}
Related
I am using recycler view pagination to show my data. I am loading one page api data by default, for next page i am loading data on the scroll basis of the recycler view. But scroll is not getting called as i can see only 1 page. If i put the condition in on scroll for increasing page no. then on scroll method its not stopping & its calling api till last page in background. Meaning on scroll is calling again and again that I don't want. I want to scroll on basis of current visible items.
live_grid.addOnScrollListener(new PaginationScrollListener(gridLayoutManager) {
#Override
protected void loadMoreItems() {
// TODO: 07/11/16 check if totalPage > 1 before triggering next load
Log.d(TAG, "live_grid loadMoreItems.......");
int visibleItemCount = gridLayoutManager.getChildCount();
int totalItemCount = gridLayoutManager.getItemCount();
int firstVisibleItemPosition = gridLayoutManager.findFirstVisibleItemPosition();
Log.d(TAG, "visibleItemCount: "+ visibleItemCount);
Log.d(TAG, "totalItemCount: "+totalItemCount);
Log.d(TAG, "firstVisibleItemPosition: "+firstVisibleItemPosition);
Log.d(TAG, "currentPage: "+currentPage);
Log.d(TAG, "PAGE_SIZE: "+PAGE_SIZE);
if (!isLoading && !isLastPage) {
// if ((visibleItemCount + firstVisibleItemPosition) >= totalItemCount && firstVisibleItemPosition >= 0) {
if ((visibleItemCount + firstVisibleItemPosition) >= totalItemCount && firstVisibleItemPosition >= 0 && currentPage < (PAGE_SIZE)) {
//&& totalItemCount >= PAGE_SIZE
firstVisibleItemPosition = visibleItemCount;
loadMoreItems1();
}
}
// presenter.setIsLoading(true);
// presenter.setCurrentPage(presenter.getCurrentPage() + 1);
// presenter.loadNextPlaylist();
}
Try this code..
protected int pastVisibleItems, visibleItemCount, totalItemCount; // define class level..
protected void addScrollListener() {
rvData.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
if (dy > 0) //check for scroll down
{
visibleItemCount = linearLayoutManager.getChildCount();
totalItemCount = linearLayoutManager.getItemCount();
pastVisibleItems = linearLayoutManager.findFirstVisibleItemPosition();
if ((visibleItemCount + pastVisibleItems) >= totalItemCount) {
pageNumber++; // increase your page
getMessage(); // call api with new Page.
}
}
}
});
}
this method used after recyclerview define and bind adapter.
GridLayoutManger..
RecyclerView.OnScrollListener scrollListener = new RecyclerView.OnScrollListener() {
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
int totalItrem = mLlManager.getItemCount();
int lastViisble = mLlManager.findLastVisibleItemPosition();
Log.d("item", "total item" + totalItrem);
Log.d("visible", "last " + lastViisble);
if (!isLoading && totalItrem == lastViisble + 1 && total_records != mEventList.size()) {
Log.e("msg", "reached end");
//Toast.makeText(mrecyclerview.getContext(), "reached at end", Toast.LENGTH_SHORT).show();
isLoading = true;
mEventList.add(null);
mCurrentPage++;
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
getData(mCurrentPage);
}
}, 2000);
}
}
};
I am going to custom a scroll listener for RecyclerView. My expectation is a button "Load more" will display when user scroll to end of list.
But I got a problem when getChildCount onScrolled() method:
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
int totalItemCount = mLayoutManager.getItemCount();
int visibleItemCount = recyclerView.getChildCount();
Log.d(TAG, "onScrolled:visibleItemCount "+visibleItemCount);
if (loading && (totalItemCount > previousTotalItemCount)) {
loading = false;
previousTotalItemCount = totalItemCount;
}
if (!loading && (visibleItemCount + visibleThreshold) > totalItemCount) {
currentPage++;
onLoadMore(currentPage, totalItemCount);
loading = true;
}
}
In the first log, visibleItemCount return the totalItemCount. For example:
onScrolled:visibleItemCount 20
onScrolled:visibleItemCount 4
etc, ....
Note:
20 is total item;
4 is the 4-th item that visible on screen
Please i am working on an android contact app which i need to load first 20 phone book contact to recycler view and use Onscroll listener to get the remaining contact to the recyclyer view when scrolling.
First add 20 item in Arraylist of Contact.on Scroll end add more item's and call adapter.notifyDataSetChanged() . This is the code to detect scroll end.
mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
visibleItemCount = mRecyclerView.getChildCount();
totalItemCount = mLayoutManager.getItemCount();
firstVisibleItem = mLayoutManager.findFirstVisibleItemPosition();
if (loading) {
if (totalItemCount > previousTotal) {
loading = false;
previousTotal = totalItemCount;
}
}
if (!loading && (totalItemCount - visibleItemCount)
<= (firstVisibleItem + visibleThreshold)) {
// End has been reached
Log.i("Yaeye!", "end called");
// Add more items into contact Arraylist and call notifyDataSetChanged()
loading = true;
}
}
});
Note : Make sure you are using LinearLayoutManager as layout manager for RecyclerView.
LinearLayoutManager mLayoutManager;
mLayoutManager = new LinearLayoutManager(this);
mRecyclerView.setLayoutManager(mLayoutManager);
I have a RecyclerView that im trying to implement an infinite scroll feature into. The issue is, the code inside the if statements in the OnScrolled method is being executed twice. Heres my current code:
public abstract class InfiniteScroll extends RecyclerView.OnScrollListener {
private LinearLayoutManager mLayoutManager;
private int previousTotal = 0;
private boolean loading = true;
private int visibleThreshold = 5;
int firstVisibleItem, visibleItemCount, totalItemCount;
private int current_page = 1;
public InfiniteScroll(LinearLayoutManager layoutManager) {
mLayoutManager = layoutManager;
}
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
visibleItemCount = recyclerView.getChildCount();
totalItemCount = mLayoutManager.getItemCount();
firstVisibleItem = mLayoutManager.findFirstVisibleItemPosition();
if (loading) {
if (totalItemCount > previousTotal) {
loading = false;
previousTotal = totalItemCount;
}
}
if (!loading && (totalItemCount - visibleItemCount)
<= (firstVisibleItem + visibleThreshold)) {
// End has been reached
// Do something
current_page++;
Log.d("moreitems", "why is this being called twice?");
loadMore(current_page);
loading = true;
}
}
public abstract void loadMore(int current_page);
}
This code was posted as an answer to a separate SO question, and other examples seem to function similar, but I still get the loadMore() method executing twice when reaching the bottom of the RecyclerView, and im not sure why.
it's getting called because when you loadMore items, onScrolled is called again.
This callback will also be called if visible item range changes after a layout calculation. In that case, dx and dy will be 0.
so you could check
if (!loading && dy>0)
as well
Try this:
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
final LinearLayoutManager linearLayoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
totalItemCount = linearLayoutManager.getItemCount();
lastVisibleItem = linearLayoutManager.findLastVisibleItemPosition();
if (!loading && totalItemCount <= (lastVisibleItem + visibleThreshold)) {
loading = true;
// End has been reached
// Do something
current_page++;
Log.d("moreitems", "why is this being called twice?");
loadMore(current_page);
}
}
I just met similar situation, while solution is quite different from the above answer.
In my case, I have a custom RecyclerViewFragment, which will set up RecyclerView at the beginning of data loading stuff. And I add a custom OnScrollListener at that set up method block.
My reason why OnScrollListener was called twice is, I accidently add two OnScrollListener to my RecyclerView. Thus these two listener will both listener to the "scroll to the end" action and do something for it.
So I just remove all the OnScrollListener for my RecyclerView before I call the set up method, to make sure that there will only be one OnScrollListener.
Hope this help.
if (layoutManager.findLastCompletelyVisibleItemPosition() ==
recyclerAdapter.getItemCount() - 1) {
//load more items code is here
}
This will work.
I'm trying to implement Endless Recyclerview in android and able to load the next set of data On scroll of RecyclerView.
But once I receive new set of data , my recycler activity is getting reloaded and items are displaying from initial data . I have even tried with EndlessScrollRecyclListener, but it was same.
Here is the code i'm trying
mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
visibleItemCount = mRecyclerView.getChildCount();
totalItemCount = mLayoutManager.getItemCount();
firstVisibleItem = mLayoutManager.findFirstVisibleItemPosition();
if (loading) {
if (totalItemCount > previousTotal) {
loading = false;
previousTotal = totalItemCount;
}
}
if (!loading && (totalItemCount - visibleItemCount)
<= (firstVisibleItem + visibleThreshold)) {
// End has been reached
new LoadData().execute(0);
loading = true;
}
}
});