In the below code example, 50 thousand Customer needs to be loaded using ListView or RecyclerView
// current process, I am using pagination to load items
List<Customer> customers = mCustomerModule.get(limit, offset);
mAdapter.addItems(customer);
Couchbase lite version 1.3
The retrieval of customers is made by views
Problem
Slow when scrolling, when reached a high amount of customers
Question
Does my pagination process slow down the performance?
Couchbase lite 1.3 views are really slow?
Goal
Improve performance
Smoothen viewing of customer list
What you are looking for is called Endless Scrolling. Take a look at this article that describe the problem and present the solution for both: with ListView and with RecyclerView:
Endless Scrolling with AdapterViews and RecyclerView
UPDATE
Here's how to implement it using a RecyclerView (info taken from above link)
Use this code as is that would be the EndlessRecyclerViewScrollListener, that will react to scrolls on the RecyclerView. So you need to set the addOnScrollListener of your RecyclerView to an instance of this 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 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);
}
Inside the mentioned onLoadMore method, load additional items into the adapter either by sending out a network request or by loading from another source.
For example:
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);
When you intend to perform a new search, make sure to clear the existing contents from the list and notify the adapter the contents have changed as soon as possible. Make sure also to reset the state of the EndlessRecyclerViewScrollListener with the resetState method:
// 1. First, clear the array of data
listOfItems.clear();
// 2. Notify the adapter of the update
recyclerAdapterOfItems.notifyDataSetChanged(); // or notifyItemRangeRemoved
// 3. Reset endless scroll listener when performing a new search
scrollListener.resetState();
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 .
I have a Recyclerview, inside NestedScrollview. Recyclerview is having different item types that need to load dynamically,But all items in recyclerview are binding together when it is inside nested scroll. How can I avoid this? I don't need any pagination. I just want to minimize the view rendering.
Try this code:
import android.support.v4.widget.NestedScrollView;
import android.support.v7.widget.RecyclerView;
import android.view.View;
public abstract class RecyclerViewByNestedScrollListener implements NestedScrollView.OnScrollChangeListener {
// 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;
// The minimum amount of pixels to have below your current scroll position
// before loading more.
private int visibleThresholdDistance = 500;
RecyclerView.LayoutManager mLayoutManager;
public RecyclerViewByNestedScrollListener(RecyclerView.LayoutManager layoutManager) {
this.mLayoutManager = layoutManager;
}
#Override
public void onScrollChange(NestedScrollView scrollView, int x, int y, int oldx, int oldy) {
// We take the last son in the scrollview
View view = scrollView.getChildAt(scrollView.getChildCount() - 1);
int distanceToEnd = (view.getBottom() - (scrollView.getHeight() + scrollView.getScrollY()));
int totalItemCount = mLayoutManager.getItemCount();
// 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 && distanceToEnd <= visibleThresholdDistance) {
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 use NestedScrollView as parent of your recyclerView. Then in code do like this:
LinearLayoutManager layoutManager=new LinearLayoutManager(this);
NestedScrollView mScrNested=(NestedScrollView)findViewById(R.id.nestedScrollView);
mScrNested.setOnScrollChangeListener(new RecyclerViewByNestedScrollListener(layoutManager) {
#Override
public void onLoadMore(int page, int totalItemsCount) {
//load next page of your recyclerView
}
});
As you see at above, you must set load more of your recyclerview with nestedScorllView. Otherwise your data load at once and your view has lagged.
All of this problem is because recyclerView not work properly inside ScrollView.
** Updated answer **
Try using Handler like below for delaying add each item to your recyclerview:
handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
yourList.add(newItem);
adapter.notifyDataSetChanged();
}
},random);//set your delay time here like 2000 for two seconds delay
I'm working with recycler view and i am working on social module like facebook and want to implement Pagination on recycler view This is my method defination
** public void getUserSharedTimeline(int userId, int lowerLimit,int upperLimit )**
Now first time I send 0 to 10 to server and get ten records. and then I call it like this.
mRecyclerView.addOnScrollListener(new EndlessScrollListener(mLayoutManager) {
#Override
public void onLoadMore(int page, int totalItemsCount) {
getUserSharedTimeline(Utilities.UserTypeId,totalItemsCount,totalItemsCount+10);
}
});
On first call
it works and get me 10 to 20 records
Then on second call it gets 20 to 21 records
and after that it's stop scrolling and do not load more data even records are more than thousand.
The pagination is also done on server side and I can't request more than 10 records at a time.
Here is my class for pagination. I checked many tutorials but in vain. Please help me in this issue.
package com.intelmanager.ithash.intelmanager.ui;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.StaggeredGridLayoutManager;
import android.widget.AbsListView;
public abstract class EndlessScrollListener extends RecyclerView.OnScrollListener {
// The minimum amount of items to have below your current scroll position
// before loading more.
private int visibleThreshold = 10;
// 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 EndlessScrollListener(RecyclerView.LayoutManager layoutManager) {
this.mLayoutManager = layoutManager;
}
public EndlessScrollListener(GridLayoutManager layoutManager) {
this.mLayoutManager = layoutManager;
visibleThreshold = visibleThreshold * layoutManager.getSpanCount();
}
public EndlessScrollListener(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);
}
I'm using StaggeredGridLayoutManager for my image gallery. I've set setReverseLayout(true), so that images get stacked from bottom.
The problem I'm facing is that at initialization of app, the scroll points at bottom of gallery. I would want the scroll to be at the top of the gallery when user first starts the app.
I've tried using scrollToPosition (the following code snippet) but then the scroll ends up somewhere in middle of gallery, probably because the images haven't loaded up properly at the time of calling scrollToPosition.
mLayoutManager = new StaggeredGridLayoutManager(2,StaggeredGridLayoutManager.VERTICAL);
mLayoutManager.setReverseLayout(true);
mRecyclerView.setLayoutManager(mLayoutManager);
mImageList = ((MainActivity)getActivity()).getImages();
adapter = new ImageAdapter(getActivity(),mImageList);
mRecyclerView.setAdapter(adapter);
mRecyclerView.scrollToPosition(mImageList.size()-1);
Is there a proper way to point the scroll at the top, rather than at the bottom?
I solved similar problem before and here is method:
mRecyclerView.getViewTreeObserver().addOnGlobalLayoutListener(
new ViewTreeObserver.OnGlobalLayoutListener() {
#SuppressWarnings("deprecation")
#Override
public void onGlobalLayout() {
ViewTreeObserver observer = mRecyclerView.getViewTreeObserver();
scrollRecyclerViewToTop();
if (!observer.isAlive()) {
return;
}
if (mScrolledByUser) {
if (hasJellyBeanApi()) {
observer.removeOnGlobalLayoutListener(this);
} else {
observer.removeGlobalOnLayoutListener(this);
}
}
}
});
And:
mRecyclerView.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
mScrollByUser = true;
return false;
}
});
And:
private void scrollRecyclerViewToTop() {
mRecyclerView.scrollToPosition(0);
mRecyclerView.scrollBy(0, Integer.MIN_VALUE);
}
The meaning is easy: let RecyclerView always scroll to top until user touches it. Hope this can help you.
try finding the first visible position by calling
findFirstCompletelyVisibleItemPositions
or findFirstVisibleItemPositions
the call your recycler view scrollToPosition with the position obtained from the previous method(s)
Try using scrollToPositionWithOffset() function of StaggeredGridLayoutManager instead. I found it more reliable than scrollToPosition. Also make sure that you execute this function inside Handler().post(). This will cause the Runnable to be added to the message queue. It will run once the UI thread is free.
new Handler().post(new Runnable() {
#Override
public void run() {
staggeredGridLayoutManager.scrollToPositionWithOffset(mImageList.size() - 1, 0);
}
});
I used scrolltoposition inside dataobserver and now it works fine..
When the recyclerview loads, items on top are visible with the below code:
rcAdapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() {
#Override
public void onItemRangeInserted(int positionStart, int itemCount) {
super.onItemRangeInserted(positionStart, itemCount);
int count = rcAdapter.getItemCount();
mRecyclerView.scrollToPosition(itemCount-1);
}
});
to scroll to the bottom for newly added items as in the chat view, use below code.
rcAdapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() {
#Override
public void onItemRangeInserted(int positionStart, int itemCount) {
super.onItemRangeInserted(positionStart, itemCount);
int count = rcAdapter.getItemCount();
int lastVisiblePositions[] = new int[2]; //for 2 columns
int lastVisiblePosition = staggeredGridLayoutManager.findLastCompletelyVisibleItemPositions(lastVisiblePositions)[0];
// If the recycler view is initially being loaded or the user is at the bottom of the list, scroll
// to the bottom of the list to show the newly added message.
if (lastVisiblePosition == -1 ||
(positionStart >= (count- 1) && lastVisiblePosition == (positionStart - 1))) {
mRecyclerView.scrollToPosition(positionStart);
}
}
});
This code may help you,I also used this link in code
https://guides.codepath.com/android/Endless-Scrolling-with-AdapterViews-and-RecyclerView
Every AdapterView (such as ListView and GridView) has support for
binding to the OnScrollListener events which are triggered whenever a
The user scrolls through the collection. Using this system, we can define
a basic EndlessScrollListener which supports most use cases by
creating our own class that extends OnScrollListener:
public abstract class EndlessScrollListener implements AbsListView.OnScrollListener {
// The minimum number 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;
public EndlessScrollListener() {
}
public EndlessScrollListener(int visibleThreshold) {
this.visibleThreshold = visibleThreshold;
}
public EndlessScrollListener(int visibleThreshold, int startPage) {
this.visibleThreshold = visibleThreshold;
this.startingPageIndex = startPage;
this.currentPage = startPage;
}
// 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 onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount)
{
// 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;
currentPage++;
}
// 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.
if (!loading && (firstVisibleItem + visibleItemCount + visibleThreshold) >= totalItemCount ) {
loading = onLoadMore(currentPage + 1, totalItemCount);
}
}
// Defines the process for actually loading more data based on page
// Returns true if more data is being loaded; returns false if there is no more data to load.
public abstract boolean onLoadMore(int page, int totalItemsCount);
#Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
// Don't take any action on changed
}
}
I want to implement Paginated list View in android so when I scroll down to the end, each time more items should add to my list, currently I am fetching 10 items from web service and showing them in a list View, now I want add 10 more Items when user scroll down to the end of the list.
Is there any way to do it?
EDIT: This one is better: http://p-xr.com/android-tutorial-dynamicaly-load-more-items-to-the-listview-never-ending-list/
-----------------------------------*----------------------
http://benjii.me/2010/08/endless-scrolling-listview-in-android/
public class EndlessScrollListener implements OnScrollListener {
private int visibleThreshold = 5;
private int currentPage = 0;
private int previousTotal = 0;
private boolean loading = true;
public EndlessScrollListener() {
}
public EndlessScrollListener(int visibleThreshold) {
this.visibleThreshold = visibleThreshold;
}
#Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
if (loading) {
if (totalItemCount > previousTotal) {
loading = false;
previousTotal = totalItemCount;
currentPage++;
}
}
if (!loading && (totalItemCount - visibleItemCount) <= (firstVisibleItem + visibleThreshold)) {
// I load the next page of gigs using a background task,
// but you can call any function here.
new LoadGigsTask().execute(currentPage + 1);
loading = true;
}
}
#Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
}
}
I found a better solution here which actually looks like an enhancements to Waza_Be's solution: https://github.com/thecodepath/android_guides/wiki/Endless-Scrolling-with-AdapterViews (I'm not the author, so credits to https://github.com/thecodepath).
An abstract listener class is implemented with an abstract method that is responsible for loading data, which is excellent for activities to send their specific requests.
I just post the code here, if somehow the code disappears in the wiki.
public abstract class EndlessScrollListener implements 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;
public EndlessScrollListener() {
}
public EndlessScrollListener(int visibleThreshold) {
this.visibleThreshold = visibleThreshold;
}
public EndlessScrollListener(int visibleThreshold, int startPage) {
this.visibleThreshold = visibleThreshold;
this.startingPageIndex = startPage;
this.currentPage = startPage;
}
// 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 onScroll(AbsListView view,int firstVisibleItem,int visibleItemCount,int totalItemCount) {
// 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;
currentPage++;
}
// 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.
if (!loading && (totalItemCount - visibleItemCount)<=(firstVisibleItem + visibleThreshold)) {
onLoadMore(currentPage + 1, totalItemCount);
loading = true;
}
}
// Defines the process for actually loading more data based on page
public abstract void onLoadMore(int page, int totalItemsCount);
#Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
// Don't take any action on changed
}
}
I think the scroll listener posted by raveN is a good way to go.
But the clean way of handling data loading in Android is to use a Loader (CursorLoader or AsyncTaskLoader, depending on where you get your data from).
And surprisingly, I couldn't find any clean way of doing paginations with loaders, so I went ahead and created a base loader that supports it. It's very early stage so feel free to submit pull requests if you find bugs:
https://github.com/nbarraille/paginated_loader
It pretty much adds a loadMore() method to the Loader, and you just have to implement loadInBackground() to load a single page of data, and appendResults() to tell the loader how to combine the results together and that's it.
The sample app uses the endless scroll listener to request more data as soon as the end of the list is reached, more data will be requested.