Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Endless scrolling with RecyclerVIew
package codepath.com.recyclerviewfun;
import java.util.ArrayList;
import java.util.List;
public class Contact {
private String mName;
private boolean mOnline;
public Contact(String name, boolean online) {
mName = name;
mOnline = online;
}
public String getName() {
return mName;
}
public boolean isOnline() {
return mOnline;
}
private static int lastContactId = 0;
public static List<Contact> createContactsList(int numContacts, int offset) {
List<Contact> contacts = new ArrayList<Contact>();
for (int i = 1; i <= numContacts; i++) {
contacts.add(new Contact("Person " + ++lastContactId + " offset: " + offset, i <= numContacts / 2));
}
return contacts;
}
}
package codepath.com.recyclerviewfun;
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;
import java.util.List;
// Create the basic adapter extending from RecyclerView.Adapter
// Note that we specify the custom ViewHolder which gives us access to our views
public class ContactsAdapter extends
RecyclerView.Adapter<ContactsAdapter.ViewHolder> {
// Store a member variable for the contacts
private List<Contact> mContacts;
// Pass in the contact array into the constructor
public ContactsAdapter(List<Contact> contacts) {
mContacts = contacts;
}
// Provide a direct reference to each of the views within a data item
// Used to cache the views within the item layout for fast access
public static class ViewHolder extends RecyclerView.ViewHolder {
// Your holder should contain a member variable
// for any view that will be set as you render a row
public TextView nameTextView;
public Button messageButton;
// We also create a constructor that accepts the entire item row
// and does the view lookups to find each subview
public ViewHolder(View itemView) {
// Stores the itemView in a public final member variable that can be used
// to access the context from any ViewHolder instance.
super(itemView);
nameTextView = (TextView) itemView.findViewById(R.id.contact_name);
messageButton = (Button) itemView.findViewById(R.id.message_button);
}
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
Context context = parent.getContext();
LayoutInflater inflater = LayoutInflater.from(context);
View contactView = inflater.inflate(R.layout.item_contact, parent, false);
ViewHolder viewHolder = new ViewHolder(contactView);
return viewHolder;
}
@Override
public void onBindViewHolder(ViewHolder viewHolder, int position) {
Contact contact = mContacts.get(position);
TextView textView = viewHolder.nameTextView;
textView.setText(contact.getName());
Button button = viewHolder.messageButton;
if (contact.isOnline()) {
button.setText("Message");
button.setEnabled(true);
}
else {
button.setText("Offline");
button.setEnabled(false);
}
}
@Override
public int getItemCount() {
return mContacts.size();
}
}
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 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 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);
}
package codepath.com.recyclerviewfun;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
import android.view.View;
import java.util.List;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
.setAction("Action", null).show();
}
});
RecyclerView rvItems = (RecyclerView) findViewById(R.id.rvContacts);
final List<Contact> allContacts = Contact.createContactsList(10, 0);
final ContactsAdapter adapter = new ContactsAdapter(allContacts);
rvItems.setAdapter(adapter);
final LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
rvItems.setLayoutManager(linearLayoutManager);
EndlessRecyclerViewScrollListener scrollListener = new EndlessRecyclerViewScrollListener(linearLayoutManager) {
@Override
public void onLoadMore(int page, int totalItemsCount, RecyclerView view) {
List<Contact> moreContacts = Contact.createContactsList(10, page);
int curSize = adapter.getItemCount();
allContacts.addAll(moreContacts);
view.post(new Runnable() {
@Override
public void run() {
adapter.notifyItemRangeInserted(curSize, allContacts.size() - 1);
}
});
}
});
rvItems.addOnScrollListener(scrollListener);
}
}
@ghost

This comment has been minimized.

Copy link

commented Apr 7, 2016

Please, can you show a similar example where the data source will be JSON? I can seem to implement this because I am using json.

@lettinghenry

This comment has been minimized.

Copy link

commented Dec 8, 2016

Well explained, thank you.

@ghanendrapiplani

This comment has been minimized.

Copy link

commented Dec 25, 2016

Can someone share implementation of this for json data?

@sriramr98

This comment has been minimized.

Copy link

commented Aug 5, 2017

Does the int page inside the scroll listener auto increment in each call from 1? I want it to auto increment from 2. How can I achieve this?

@BambangHeriSetiawan

This comment has been minimized.

Copy link

commented Feb 13, 2018

@ghost maybe this can help u.

##implement in adapter

public void onUpdateItemPlaces(List<ResponseCategoriesById.Data.PlacesItem> placesItems) { if (this.placesItems.size() != 0) { this.placesItems.clear(); } this.placesItems = placesItems; notifyItemChanged(getItemCount()); }

##implemen in activity

`@override
public void initPlaces(List places, Integer placeCurrentPage, Integer placePerPage, Integer placeTotalItem, String placeNextPage) {
adapter.onAddItemPlaces(places);
rcvPlaces.setAdapter(adapter);

    rcvPlaces.addOnScrollListener(new EndlessRecyclerOnScrollListener() {
        @Override
        public void onLoadMore() {
            Log.e("", "onLoadMore: " + placeCurrentPage );
            if (placeCurrentPage !=null && placeNextPage != null){
                placePresenter.getPlaces(idPlace,placeCurrentPage+1);
            }
        }
    });
}`

thanks.
data get from JSON

@nguyenhoangphuc96

This comment has been minimized.

Copy link

commented Jun 4, 2018

How to add progress bar when it loading?

@olimdzhon

This comment has been minimized.

Copy link

commented Oct 29, 2018

i'm trying to scroll up my Recycleview after getting to the bottom using your sample and it's shows me only last 5 items of Recycleview how can i handle it?

@adityasonel

This comment has been minimized.

Copy link

commented Dec 20, 2018

It's not working when RecyclerView is placed in NestedScrollView. How to do it ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.