Infinite Scrolling in Android

Posted By : Rahul Baboria | 30-Nov-2017

Infinite scroll is used when we have very large amount of data i.e. say we have to populate a list with more than hundred items , here we have to load items in asynchronously. When we reach bottom we have to hit another API for more data. If we populate whole data at once , it will consume time to load that much of data and then it will effect the scrolling of recyclerview as well. 

 

We will implement infinite scroll API in this blog covering from showing loader at the end of list and then populating the list as we reach the bottom of list.

 

Implementation:

As we know about homogenous recycler view adapter which shows simmilar type of items but in case of this we need to use hetrogenous adapter for populating recyclerview according with loader at end and other items above it. Please see the following class for creating recyclerview adapter with two views :

 

import android.content.Context;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import java.util.List;
public class MyRecyclerViewAdapter extends RecyclerView.Adapter<MyViewHolder> {
    private List<String> itemList;
    protected Context context;
    private int visibleThreshold = 5;
    private int lastVisibleItem, totalItemCount;
    private boolean loading;
    private OnLoadMoreListener onLoadMoreListener;
    public MyRecyclerViewAdapter(Context context, List<String> itemList, RecyclerView recyclerView) {
        this.itemList = itemList;
        this.context = context;
        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)){
                        if(onLoadMoreListener != null){
                            onLoadMoreListener.onLoadMore();
                        }
                        loading = true;
                    }
                }
            });
        }
    }
    @Override
    public int getItemViewType(int position) {
        return itemList.get(position) != null ? 1 : 0;
    }
    @Override
    public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        RecyclerViewHolders viewHolder = null;
        if(viewType == 1){
            View layoutView = LayoutInflater.from(parent.getContext()).inflate(R.layout.normal_item, parent, false);
            viewHolder = new MyViewHolder(layoutView);
        }else{
            View layoutView = LayoutInflater.from(parent.getContext()).inflate(R.layout.progress_item, parent, false);
            viewHolder = new ProgressViewHolder(layoutView);
        }
        return viewHolder;
    }
    @Override
    public void onBindViewHolder(RecyclerViewHolders holder, int position) {
        if(holder instanceof RecyclerViewHolders){
            ((RecyclerViewHolders)holder).textTitle.setText(itemList.get(position));
        }else{
            ((ProgressViewHolder)holder).progressBar.setIndeterminate(true);
        }
    }
    public void setLoad(){
        loading = false;
    }
    @Override
    public int getItemCount() {
        return this.itemList.size();
    }
    public void setOnLoadMoreListener(OnLoadMoreListener onLoadMoreListener){
        this.onLoadMoreListener = onLoadMoreListener;
    }
    public interface OnLoadMoreListener {
        void onLoadMore();
    }
    public void setDataLoaded() {
        loading = false;
    }
}

Create two seperate layout files for our adapter , one for list items and other for showing loader. We are using  View Holder pattern in the adapter, we will create two different viewholder classes that will extends from the RecyclerView.Holder class. We are implementing our logic of by applying AddOnScrolllistener to recyclerview and calculate the threshhold there and apply logic with respect to visible items and last visible item by simply getting total and last visible item by layout manager.

 

MyViewHolder.class :

Create the MyViewHolder class in your project for recyclerview items (Single List Item).

import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
public class MyViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
    public ImageView displayedImage;
    public TextView textTitle;
    public MyViewHolder(View itemView) {
        super(itemView);
        itemView.setOnClickListener(this);
        textTitle = (TextView)itemView.findViewById(R.id.title_header);
    }
    @Override
    public void onClick(View view) {
    }
}

 

ProgressViewHolder.class :

Create the ProgressViewHolder class in your project for showing loader at bottom of screen.

import android.view.View;
import android.widget.ProgressBar;
public class ProgressViewHolder extends RecyclerViewHolders{
    public ProgressBar progressBar;
    public ProgressViewHolder(View itemView) {
        super(itemView);
        progressBar = (ProgressBar)itemView.findViewById(R.id.progressBar);
    }
}

 

At last inside our activity or fragment file where we have added recycler view. We will initialize recycler view. We will get the instance of the RecyclerView inside adapter , set a LinearLayourManager object also to it. In the setAdapter method of the class , we will pass an instance of the RecyclerView Adapter we created. Apply loadmore listener on recyclerview and add null to the end of list , every object of list which is null it will show loader, So in this case when we will add more data to list , we have to remove null from it and add another list to current list.

 

 

 

        myAdapter.setOnLoadMoreListener(new MyAdapter.OnLoadMoreListener() {
            @Override
            public void onLoadMore() {
                list.add(null);
                myAdapter.notifyItemInserted(list.size() - 1);
                handler.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        adapterData.remove(list.size() - 1);
                        myAdapter.notifyItemRemoved(list.size());
                        for (int i = 0; i < 15; i++) {
                            list.add("List" + (list.size() + 1));
                            myAdapter.notifyItemInserted(list.size());
                        }
                        myAdapter.setDataLoaded();
                    }
                }, 2000);
                System.out.println("load");
            }
        });

 

Thanks.

 

 

 

 

About Author

Author Image
Rahul Baboria

Rahul Baboria is having good knowledge over Android Application.

Request for Proposal

Name is required

Comment is required

Sending message..