How to Implement Endless List With Recyclerview

How to implement endless list with RecyclerView?

Thanks to @Kushal and this is how I implemented it

private boolean loading = true;
int pastVisiblesItems, visibleItemCount, totalItemCount;

mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
if (dy > 0) { //check for scroll down
visibleItemCount = mLayoutManager.getChildCount();
totalItemCount = mLayoutManager.getItemCount();
pastVisiblesItems = mLayoutManager.findFirstVisibleItemPosition();

if (loading) {
if ((visibleItemCount + pastVisiblesItems) >= totalItemCount) {
loading = false;
Log.v("...", "Last Item Wow !");
// Do pagination.. i.e. fetch new data

loading = true;
}
}
}
}
});

Don't forget to add

LinearLayoutManager mLayoutManager;
mLayoutManager = new LinearLayoutManager(this);
mRecyclerView.setLayoutManager(mLayoutManager);

How to implement endless scroll (pagination) in recyclerview with StaggeredGridLayoutManager

For your first problem you already have a solution.

StaggeredGridLayoutManager staggeredGridLayoutManager = new 
StaggeredGridLayoutManager(3, StaggeredGridLayoutManager.VERTICAL);
postRecyclerView.setLayoutManager(
staggeredGridLayoutManager // I have 3 rows
);

For second problem:

postRecyclerView.setOnScrollListener(new RecyclerView.OnScrollListener({
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {

visibleItemCount = staggeredGridLayoutManager .getChildCount();
totalItemCount = staggeredGridLayoutManager .getItemCount();
int[] firstVisibleItems = null;
firstVisibleItems = mLayoutManager.findFirstVisibleItemPositions(firstVisibleItems);
if(firstVisibleItems != null && firstVisibleItems.length > 0) {
pastVisibleItems = firstVisibleItems[0];
}

if (loading) {
if ((visibleItemCount + pastVisibleItems) >= totalItemCount) {
loading = false;
getData()
}
}
}
});
..........
..........
private void getData() {
mStorage = FirebaseStorage.getInstance();
databaseEventListener = databaseReference.addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot snapshot) {
if (snapshot.exists()) {
progressBar.setVisibility(View.GONE);
postRecyclerView.setVisibility(View.VISIBLE);
mUploads.clear();
for (DataSnapshot dataSnapshot : snapshot.getChildren()) {
Upload upload = dataSnapshot.getValue(Upload.class);
Objects.requireNonNull(upload).setmKey(dataSnapshot.getKey());
mUploads.add(upload);
}
}
//notify the adapter
postsAdapter.notifyDataSetChanged();
loading = true;
}

@Override
public void onCancelled(@NonNull DatabaseError error) {
loading = true;
}
});
}

You might have to call the getData() initially in your onCreate() so that some data loads up on the screen and you have a scroll behavior.

Update:
The second parameter in a StaggeredGridLayoutManager is orientation so instead of context you have to pass orientation StaggeredGridLayoutManager.VERTICAL.

Implementing Endless RecyclerView

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

How do I create a circular (endless) RecyclerView?

There is no way of making it infinite, but there is a way to make it look like infinite.

  1. in your adapter override getCount() to return something big like Integer.MAX_VALUE:

    @Override
    public int getCount() {
    return Integer.MAX_VALUE;
    }
  2. in getItem() and getView() modulo divide (%) position by real item number:

    @Override
    public Fragment getItem(int position) {
    int positionInList = position % fragmentList.size();
    return fragmentList.get(positionInList);
    }
  3. at the end, set current item to something in the middle (or else, it would be endless only in downward direction).

    // scroll to middle item
    recyclerView.getLayoutManager().scrollToPosition(Integer.MAX_VALUE / 2);

How to make endless scrolling in RecyclerView Using Kotlin

    boolean loading = true;
int pastItemsVisible, visibleItemCount, totalItemCount;

mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
if (dy > 0) { //check for scroll down
visibleItemCount = mLayoutManager.getChildCount();
totalItemCount = mLayoutManager.getItemCount();
pastItemsVisible = mLayoutManager.findFirstVisibleItemPosition();

if (loading) {
if ((visibleItemCount + pastItemsVisible) >= totalItemCount) {
loading = false;

Log.v("...", "Last Item !");

// Do pagination.. i.e. fetch new data

loading = true;
}
}
}
}
});

Endless RecyclerView, that repeat data when goes to the end

You are lucky, I did it a couple of days ago.

The trick in my solution was to override the getItemCount() of the adapter so that it works with Integer.MAX_VALUE value.

The getItemCount() is used by the recyclerview to determinate how many items there are in the list, and if it returns always MAX_VALUE, the list is pretty much infinite.

This is my example:

Activity

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.mlayout);
RecyclerView myRv = findViewById(R.id.myRv);

ArrayList<MyObject> objectList = new ArrayList<>();
objectList = retrieveObjectList();
myRv.setLayoutManager(new SlowLayoutManager(myActivity.this));
MyAdapter myAdapter = new MyAdapter(objectList);
myRv.setAdapter(myAdapter);

}

Adapter

public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> {

private ArrayList<MyObject> myObjects;

public MyAdapter(ArrayList<MyObject> myObjects) {
this.myObjects = myObjects;
}

//used to retrieve the effective item position in list
public int getActualItemCount() {
if (myObjects == null) {
myObjects = new ArrayList<>();
}
return myObjects.size();
}

@Override
public int getItemCount() {
return Integer.MAX_VALUE;
}

@NonNull
@Override
public MyAdapter.MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
return new MyAdapter.MyViewHolder(LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_view, parent, false));
}

@Override
public void onBindViewHolder(@NonNull MessagesAdapter.MessagesViewHolder holder, int position) {
if (myObjects.size() == 0) {
holder.bind(null);
} else {
MyObject myObject = myObjects.get(position % myObjects.size());
holder.bind(SMSMessage);
}
}

class MyViewHolder extends RecyclerView.ViewHolder {

TextView myTv;

MessagesViewHolder(View itemView) {
super(itemView);
myTv = itemView.findViewById(R.id.myTv);
}

void bind(MyObject myObject) {
if (myObject != null) {
myTv.setText(myObject.getProperty());
} else {
myTv.setText("");
}
}
}
}

I use this way (obj I changed names so you can fill them with yours, since some of mine were similar to native ones).

If you have any question, ask freely

Adding items to Endless Scroll RecyclerView with ProgressBar at bottom

The problem is that when you add new item internal EndlessRecyclerOnScrollListener doesn't know about it and counters breaking.
As a matter of fact answer with EndlessRecyclerOnScrollListener has some limitations and possible problems, e.g. if you load 1 item at a time it will not work. So here is an enhanced version.

  1. Get rid of EndlessRecyclerOnScrollListener we don't need it anymore
  2. Change your adapter to this which contains scroll listener

    public class MyAdapter<T> extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

    private final int VIEW_ITEM = 1;
    private final int VIEW_PROG = 0;

    private List<T> mDataset;

    // The minimum amount of items to have below your current scroll position before loading more.
    private int visibleThreshold = 2;
    private int lastVisibleItem, totalItemCount;
    private boolean loading;
    private OnLoadMoreListener onLoadMoreListener;

    public MyAdapter(List<T> myDataSet, RecyclerView recyclerView) {
    mDataset = myDataSet;

    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);

    totalItemCount = linearLayoutManager.getItemCount();
    lastVisibleItem = linearLayoutManager.findLastVisibleItemPosition();
    if (!loading && totalItemCount <= (lastVisibleItem + visibleThreshold)) {
    // End has been reached
    // Do something
    if (onLoadMoreListener != null) {
    onLoadMoreListener.onLoadMore();
    }
    loading = true;
    }
    }
    });
    }
    }

    @Override
    public int getItemViewType(int position) {
    return mDataset.get(position) != null ? VIEW_ITEM : VIEW_PROG;
    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    RecyclerView.ViewHolder vh;
    if (viewType == VIEW_ITEM) {
    View v = LayoutInflater.from(parent.getContext())
    .inflate(android.R.layout.simple_list_item_1, parent, false);

    vh = new TextViewHolder(v);
    } else {
    View v = LayoutInflater.from(parent.getContext())
    .inflate(R.layout.progress_item, parent, false);

    vh = new ProgressViewHolder(v);
    }
    return vh;
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
    if (holder instanceof TextViewHolder) {
    ((TextViewHolder) holder).mTextView.setText(mDataset.get(position).toString());
    } else {
    ((ProgressViewHolder) holder).progressBar.setIndeterminate(true);
    }
    }

    public void setLoaded() {
    loading = false;
    }

    @Override
    public int getItemCount() {
    return mDataset.size();
    }

    public void setOnLoadMoreListener(OnLoadMoreListener onLoadMoreListener) {
    this.onLoadMoreListener = onLoadMoreListener;
    }

    public interface OnLoadMoreListener {
    void onLoadMore();
    }

    public static class TextViewHolder extends RecyclerView.ViewHolder {
    public TextView mTextView;

    public TextViewHolder(View v) {
    super(v);
    mTextView = (TextView) v.findViewById(android.R.id.text1);
    }
    }

    public static class ProgressViewHolder extends RecyclerView.ViewHolder {
    public ProgressBar progressBar;

    public ProgressViewHolder(View v) {
    super(v);
    progressBar = (ProgressBar) v.findViewById(R.id.progressBar);
    }
    }
    }
  3. Change code in Activity class

    mAdapter = new MyAdapter<String>(myDataset, mRecyclerView);
    mRecyclerView.setAdapter(mAdapter);

    mAdapter.setOnLoadMoreListener(new MyAdapter.OnLoadMoreListener() {
    @Override
    public void onLoadMore() {
    //add progress item
    myDataset.add(null);
    mAdapter.notifyItemInserted(myDataset.size() - 1);

    handler.postDelayed(new Runnable() {
    @Override
    public void run() {
    //remove progress item
    myDataset.remove(myDataset.size() - 1);
    mAdapter.notifyItemRemoved(myDataset.size());
    //add items one by one
    for (int i = 0; i < 15; i++) {
    myDataset.add("Item" + (myDataset.size() + 1));
    mAdapter.notifyItemInserted(myDataset.size());
    }
    mAdapter.setLoaded();
    //or you can add all at once but do not forget to call mAdapter.notifyDataSetChanged();
    }
    }, 2000);
    System.out.println("load");
    }
    });

The rest remains unchanged, let me know if this works for you.



Related Topics



Leave a reply



Submit