Android Endless List

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

Android Endless List

One solution is to implement an OnScrollListener and make changes (like adding items, etc.) to the ListAdapter at a convenient state in its onScroll method.

The following ListActivity shows a list of integers, starting with 40, adding items when the user scrolls to the end of the list.

public class Test extends ListActivity implements OnScrollListener {

Aleph0 adapter = new Aleph0();

protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setListAdapter(adapter);
getListView().setOnScrollListener(this);
}

public void onScroll(AbsListView view,
int firstVisible, int visibleCount, int totalCount) {

boolean loadMore = /* maybe add a padding */
firstVisible + visibleCount >= totalCount;

if(loadMore) {
adapter.count += visibleCount; // or any other amount
adapter.notifyDataSetChanged();
}
}

public void onScrollStateChanged(AbsListView v, int s) { }

class Aleph0 extends BaseAdapter {
int count = 40; /* starting amount */

public int getCount() { return count; }
public Object getItem(int pos) { return pos; }
public long getItemId(int pos) { return pos; }

public View getView(int pos, View v, ViewGroup p) {
TextView view = new TextView(Test.this);
view.setText("entry " + pos);
return view;
}
}
}

You should obviously use separate threads for long running actions (like loading web-data) and might want to indicate progress in the last list item (like the market or gmail apps do).

How to implement endless scrolling listview

you didn't use EndlessListView in your Fragment. As I looked your response, it includes pagination. So, you need to request with page number to use endless scroll.

This is just flow for Endless Listview. If your code still doesn't work, I hope you can learn sample projects after read this messages. I added only parts you need. Thanks

Endless scroll only shows limited data on listview. When user scroll down to bottom, it will get next limited data from server. So you need to add current_page paramater in your request. I don't know exactly your api.

First, you need variable for current_page which initialize with 0

You have to know when to stop. You response has total_page field for that. Save and add validation

Then you need to know when to request next page. For that,you already have codes in onScroll within EndlessListView. That code calculate and tell when user scroll down to bottom and it called

listener.loadData();

to request new data. But you still need to add listener for that. You already have

public void setListener(EndLessListener listener) {
this.listener = listener;
}

You need to create Interface with the name EndlessListener and implements in your fragment. EndlessListener Interface will include loadData() function that request to server. After that you need to add listener for the listview.

endlessListView.setListener(this);

Endless Scrolling RecyclerView is not working when items in list are minimum then screen size

You can do your load more task something like this in recyclerview if list are minimum then screen size

@Override
public void onBindViewHolder(DataObjectHolder holder, int position) {
holder.label.setText(mDataset.get(position).getmText1());
holder.dateTime.setText(mDataset.get(position).getmText2());

if (position == this.getItemCount() - 1 && !loading){
// do your load more task here
}
}

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

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 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.

Endless Scroll RecyclerView always return to top

set adapter in onCreateView()

   @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
View view = inflater.inflate(R.layout.booking_fragment, container, false);

recyclerView = (RecyclerView) view.findViewById(R.id.bookingRecyclerView);
linearLayoutManager = new LinearLayoutManager(getActivity());
recyclerView.setLayoutManager(linearLayoutManager);

adapter = new BookingAdapter(listBooking,getActivity());
recyclerView.setAdapter(adapter);

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


if(CurrentStatus.equals("notSearch")){
if (current < Integer.parseInt(TP)) {
current++;
loadMoreBookings(sort);
}
else if(current == Integer.parseInt(TP)){
Toast.makeText(getActivity(),"No More Data to Load", Toast.LENGTH_SHORT).show();
}
}else{
if (current < Integer.parseInt(TP)) {
current++;
searchMoreBookings(search, sort);
}
else if(current == Integer.parseInt(TP)){
Toast.makeText(getActivity(),"No More Data to Be Load", Toast.LENGTH_SHORT).show();
}
}
}

don't set adapter every time just notify the adapter item inserted at position.

private void loadMoreBookings(final String sort){
CurrentStatus = "notSearch";
final ProgressDialog progressDialog = new ProgressDialog(getActivity());
progressDialog.setMessage("Please Wait While Retrieving Data");
progressDialog.setCancelable(false);
progressDialog.show();
StringRequest requesting = new StringRequest(Request.Method.POST, URL,
new Response.Listener<String>() {
@Override
public void onResponse(String JSONString) {
progressDialog.dismiss();
try{
JSONObject jsonTP = new JSONObject(JSONString);
JSONArray jsonArrayB = jsonTP.getJSONArray("Data");
for(int i = 0; i < jsonArrayB.length(); i++){
JSONObject o = jsonArrayB.getJSONObject(i);
Booking list = new Booking(
o.getString("bookID"),
o.getString("userEmail"),
o.getString("paymentMethod"),
o.getString("paymentStatus"),
o.getString("totalPrice"),
o.getString(String.valueOf("securityCode")),
o.getString(String.valueOf("travelDate")),
o.getString("paymentID"),
o.getString("userFN"),
o.getString("userLN"),
o.getString(String.valueOf("createdAt")),
o.getString("tTM"),
o.getString("messageToCustomer"),
o.getString("messageFromMerchant"),
o.getString("wCN"),
o.getString("wLocation"),
o.getString("wWebsite")
);
listBooking.add(list);
adapter.notifyItemInserted(count);
count++;
}
Toast.makeText(getActivity(), "Data : "+count, Toast.LENGTH_SHORT).show();

} catch (JSONException e) {
loadMoreBookings(sort);
}
}
},
new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
progressDialog.dismiss();
Toast.makeText(getActivity().getApplicationContext(), "Failed To Retrieve Data. Please Try Again.",Toast.LENGTH_LONG).show();
}
}
){
@Override
protected Map<String, String> getParams() throws AuthFailureError {
Map<String,String> params = new HashMap<String, String>();
String user = getActivity().getIntent().getStringExtra("username");
params.put("username", user);
params.put("currentpage", String.valueOf(current));
params.put("sorting", sort);
return params;
}
};
RequestQueue requestQueue = Volley.newRequestQueue(getActivity().getApplicationContext());
requestQueue.add(requesting);
}


Related Topics



Leave a reply



Submit