javaandroid-cardviewandroid-recyclerviewonscrolllistenerendlessscroll

How to implement setOnScrollListener in RecyclerView


How Do I show progress bar at bottom when user reached to items those are visible in a list.

I have written a code in which i am getting data using web service, now i would like to populate partial records, because i have around 630 records in my JSON.

Here is my whole code which i am using to get data from JSON and to populate into RecyclerView.

Here is how my JSON looks, but real JSON contains over 600 records:

 http://walldroidhd.com/api.php

Can someone guide me where i have to make changes in my code ?

I want to populate more records whenever user do scroll to bottom using progressbar, still i am showing all the records.

RecyclerViewFragment.java:

public class RecyclerViewFragment extends Fragment {

    RecyclerView mRecyclerView;
    LinearLayoutManager mLayoutManager;
    RecyclerView.Adapter mAdapter;
    ArrayList<NatureItem> actorsList;

    private int previousTotal = 0;
    private boolean loading = true;
    private int visibleThreshold = 5;
    int firstVisibleItem, visibleItemCount, totalItemCount;

    public static RecyclerViewFragment newInstance() {
        return new RecyclerViewFragment();
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_recyclerview_advance, container, false);
    }

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        actorsList = new ArrayList<NatureItem>();

        new JSONAsyncTask().execute("my JSON url");

        mRecyclerView = (RecyclerView) view.findViewById(R.id.recycler_view);
        mRecyclerView.setHasFixedSize(true);

        mLayoutManager = new GridLayoutManager(getActivity(), 2);
        mRecyclerView.setLayoutManager(mLayoutManager);

        mRecyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() {

            @Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);

                visibleItemCount = mRecyclerView.getChildCount();
                totalItemCount = mLayoutManager.getItemCount();
                firstVisibleItem = mLayoutManager.findFirstVisibleItemPosition();

                if (loading) {
                    if (totalItemCount > previousTotal) {
                        loading = false;
                        previousTotal = totalItemCount;
                    }
                }
                if (!loading && (totalItemCount - visibleItemCount)
                        <= (firstVisibleItem + visibleThreshold)) {
                    // End has been reached

                    Log.i("...", "end called");

                    // Do something

                    loading = true;
                }
            }
        });

        // mAdapter = new CardAdapter();
        mAdapter = new RecyclerViewMaterialAdapter(new CardAdapter(getActivity(), actorsList), 2);
        mRecyclerView.setAdapter(mAdapter);

        MaterialViewPagerHelper.registerRecyclerView(getActivity(), mRecyclerView, null);

        mRecyclerView.addOnItemTouchListener(
                new RecyclerItemClickListener(getActivity(), new RecyclerItemClickListener.OnItemClickListener() {
                    @Override
                    public void onItemClick(View view, int position) {

                        Toast.makeText(getActivity(), String.valueOf(position), Toast.LENGTH_LONG).show();

                    }
                })
        );

    }

    class JSONAsyncTask extends AsyncTask<String, Void, Boolean> {

        ProgressDialog dialog;

        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            dialog = new ProgressDialog(getActivity());
            dialog.setMessage("Loading, please wait");
            dialog.setTitle("Connecting server");
            dialog.show();
            dialog.setCancelable(false);
        }

        @Override
        protected Boolean doInBackground(String... urls) {
            try {

                //------------------>>
                HttpGet httppost = new HttpGet(urls[0]);
                HttpClient httpclient = new DefaultHttpClient();
                HttpResponse response = httpclient.execute(httppost);

                // StatusLine stat = response.getStatusLine();
                int status = response.getStatusLine().getStatusCode();

                if (status == 200) {
                    HttpEntity entity = response.getEntity();
                    String data = null;
                    try {
                        data = EntityUtils.toString(entity);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }


                    JSONObject jsono = null;
                    try {
                        jsono = new JSONObject(data);
                    } catch (JSONException e) {
                        e.printStackTrace();
                    }
                    JSONArray jarray = jsono.getJSONArray("wallpapers");


                    for (int i = 0; i < jarray.length(); i++) {
                        JSONObject object = jarray.getJSONObject(i);

                        NatureItem actor = new NatureItem();

                        actor.setName(object.getString("id"));
                        actor.setThumbnail(object.getString("thumb_url"));

                        actorsList.add(actor);
                    }
                    return true;
                }

                //------------------>>

            } catch (ParseException e1) {
                e1.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } catch (JSONException e) {
                e.printStackTrace();
            }
            return false;
        }

        protected void onPostExecute(Boolean result) {
            dialog.cancel();
            mAdapter.notifyDataSetChanged();
            if (result == false) {
                Toast.makeText(getActivity(), "Unable to fetch data from server", Toast.LENGTH_LONG).show();
            }
            else {

            }

        }
    }
}

CardAdapter.java:

public class CardAdapter extends RecyclerView.Adapter<CardAdapter.ViewHolder> {

    private ArrayList<NatureItem> mItems;
    private Context mContext;

    public CardAdapter(Context context, ArrayList<NatureItem> feedItemList) {
        this.mItems = feedItemList;
        this.mContext = context;
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
        View v = LayoutInflater.from(viewGroup.getContext())
                .inflate(R.layout.recycler_view_card_item, viewGroup, false);

        ViewHolder viewHolder = new ViewHolder(v);
        return viewHolder;
    }

    @Override
    public void onBindViewHolder(ViewHolder viewHolder, int i) {
        NatureItem nature = mItems.get(i);
        viewHolder.tvNature.setText(nature.getName());

        Picasso.with(mContext).load(nature.getThumbnail())
                .error(R.mipmap.ic_launcher)
                .placeholder(R.mipmap.ic_launcher)
                .into(viewHolder.imgThumbnail);

    }

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

    class ViewHolder extends RecyclerView.ViewHolder{

        public ImageView imgThumbnail;
        public TextView tvNature;

        public ViewHolder(View itemView) {
            super(itemView);
            imgThumbnail = (ImageView)itemView.findViewById(R.id.img_thumbnail);
            tvNature = (TextView)itemView.findViewById(R.id.tv_nature);
        }
    }
}

Here is how i have implemented Endless as well, using this:

mRecyclerView.setOnScrollListener(new EndlessRecyclerOnScrollListener(linearLayoutManager) {
            @Override
            public void onLoadMore(int current_page) {
                // do something...
            }
        });

Note: I would personally prefer RecyclerView onScroll functionality to get my work done.


Solution

  • Activity Class with recylcerview in xml layout file

    public class WallpaperActivity extends AppCompatActivity implements OnTaskCompleted {
    
    
    private static final String TAG = "WallpaperActivity";
    
    
    private Toolbar toolbar;
    
    
    private RecyclerView mRecyclerView;
    private WallPaperDataAdapter mAdapter;
    private LinearLayoutManager mLayoutManager;
    // to keep track which pages loaded and next pages to load
    public static int pageNumber;
    
    private List<WallPaper> wallpaperImagesList;
    
    
    protected Handler handler;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.wallpaper_main);
        toolbar = (Toolbar) findViewById(R.id.toolbar);
        mRecyclerView = (RecyclerView) findViewById(R.id.my_recycler_view);
        pageNumber = 1;
        wallpaperImagesList = new ArrayList<WallPaper>();
        handler = new Handler();
        if (toolbar != null) {
            setSupportActionBar(toolbar);
            getSupportActionBar().setTitle("WallPapers");
    
        }
    
    
        // use this setting to improve performance if you know that changes
        // in content do not change the layout size of the RecyclerView
        mRecyclerView.setHasFixedSize(true);
    
    
        mLayoutManager = new LinearLayoutManager(this);
    
    
        // use a linear layout manager
        mRecyclerView.setLayoutManager(mLayoutManager);
    
    
        // create an Object for Adapter
        mAdapter = new WallPaperDataAdapter(wallpaperImagesList, mRecyclerView);
    
        // set the adapter object to the Recyclerview
        mRecyclerView.setAdapter(mAdapter);
    
    
        getWebServiceData();
    
    
        mAdapter.setOnLoadMoreListener(new OnLoadMoreListener() {
            @Override
            public void onLoadMore() {
                //add null , so the adapter will check view_type and show progress bar at bottom
                wallpaperImagesList.add(null);
                mAdapter.notifyItemInserted(wallpaperImagesList.size() - 1);
                ++pageNumber;
    
    
                getWebServiceData();
    
    
            }
        });
    
    
    }
    
    
    public void getWebServiceData() {
    
        BackGroundTask backGroundTask = new BackGroundTask(this, this, pageNumber);
        backGroundTask.execute();
    
    }
    
    
    @Override
    public void onTaskCompleted(String response) {
    
    
        parsejosnData(response);
    
    }
    
    
    public void parsejosnData(String response) {
    
        try {
    
            JSONObject jsonObject = new JSONObject(response);
    
            //    String json = jsonObject.toString();
    
            JSONArray jsonArray = jsonObject.getJSONArray("wallpapers");
    
    
            if (jsonArray != null) {
                // looping through All albums
    
    
                if (pageNumber > 1) {
                    wallpaperImagesList.remove(wallpaperImagesList.size() - 1);
                    mAdapter.notifyItemRemoved(wallpaperImagesList.size());
                }
    
                for (int i = 0; i < jsonArray.length(); i++) {
                    JSONObject c = jsonArray.getJSONObject(i);
    
                    // Storing each json item values in variable
                    String id = c.getString("id");
                    String orig_url = c.getString("orig_url");
                    String thumb_url = c.getString("thumb_url");
                    String downloads = c.getString("downloads");
                    String fav = c.getString("fav");
    
                    // Creating object for each product
                    WallPaper singleWall = new WallPaper(id, orig_url, thumb_url, downloads, fav);
    
                    // adding HashList to ArrayList
                    wallpaperImagesList.add(singleWall);
    
    
                    handler.post(new Runnable() {
                        @Override
                        public void run() {
                           mAdapter.notifyItemInserted(wallpaperImagesList.size());
    
    
                        }
                    });
    
    
                }
    
    
                mAdapter.setLoaded();
    
    
            } else {
                Log.d("Wallpapers: ", "null");
            }
    
        } catch (JSONException e) {
            e.printStackTrace();
        }
    
    }
    
    
    }
    

    Adapter Class

    public class WallPaperDataAdapter extends RecyclerView.Adapter {
        private final int VIEW_ITEM = 1;
        private final int VIEW_PROG = 0;
    
        private List<WallPaper> imagesList;
    
        // The minimum amount of items to have below your current scroll position
        // before loading more.
        private int visibleThreshold = 5;
        private int lastVisibleItem, totalItemCount;
        private boolean loading;
        private OnLoadMoreListener onLoadMoreListener;
    
    
        public WallPaperDataAdapter(List<WallPaper> imagesList1, RecyclerView recyclerView) {
            imagesList = imagesList1;
    
            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 imagesList.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(
                        R.layout.wallpaper_row, parent, false);
    
                vh = new WallPaperViewHolder(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 WallPaperViewHolder) {
    
                WallPaper singleWallPaper = (WallPaper) imagesList.get(position);
    
    
                Glide.with(((WallPaperViewHolder) holder).thumbIcon.getContext())
                        .load(singleWallPaper.getThumbUrl())
                        .centerCrop()
                        .placeholder(R.drawable.bg)
                        .crossFade()
                        .into(((WallPaperViewHolder) holder).thumbIcon);
    
    
            } else {
                ((ProgressViewHolder) holder).progressBar.setIndeterminate(true);
            }
        }
    
        public void setLoaded() {
            loading = false;
        }
    
        @Override
        public int getItemCount() {
            return imagesList.size();
        }
    
        public void setOnLoadMoreListener(OnLoadMoreListener onLoadMoreListener) {
            this.onLoadMoreListener = onLoadMoreListener;
        }
    
    
        //
        public static class WallPaperViewHolder extends RecyclerView.ViewHolder {
    
    
            public ImageView thumbIcon;
    
    
            public WallPaperViewHolder(View v) {
                super(v);
    
    
                thumbIcon = (ImageView) v.findViewById(R.id.thumbIcon);
    
    
            }
        }
    
        public static class ProgressViewHolder extends RecyclerView.ViewHolder {
            public ProgressBar progressBar;
    
            public ProgressViewHolder(View v) {
                super(v);
                progressBar = (ProgressBar) v.findViewById(R.id.progressBar1);
            }
        }
    }
    

    wallpaper_row.xml

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
    
    <ImageView
        android:id="@+id/thumbIcon"
        android:layout_width="160dp"
        android:layout_height="160dp"
        android:layout_centerInParent="true"
        android:layout_margin="2dp"
        android:gravity="center" />
    
    </RelativeLayout>
    

    progress_item.xml

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical" >
    
        <ProgressBar
            android:id="@+id/progressBar1"
            android:layout_width="wrap_content"
            android:layout_gravity="center"
            android:layout_height="wrap_content" />
    
    </LinearLayout>
    

    Separate BackGroundTask.java

    public class BackGroundTask extends AsyncTask<Object, Void, String> {
    
        private ProgressDialog pDialog;
        public OnTaskCompleted listener = null;//Call back interface
    
    
        Context context;
        int pageNumber;
    
        public BackGroundTask(Context context1, OnTaskCompleted listener1, int pageNumber) {
            context = context1;
            listener = listener1;   //Assigning call back interface  through constructor
            this.pageNumber = pageNumber;
        }
    
        @Override
        protected void onPreExecute() {
            super.onPreExecute();
    
        }
    
        @Override
        protected String doInBackground(Object... params) {
    
            //My Background tasks are written here
    
            synchronized (this) {
    
                String url = Const.URL_WALLPAPERS_HD + pageNumber;
                String jsonStr = ServiceHandler.makeServiceCall(url, ServiceHandler.GET);
                Log.i("Url: ", "> " + url);
    
                Log.i("Response: ", "> " + jsonStr);
                return jsonStr;
            }
    
        }
    
        @Override
        protected void onPostExecute(String result) {
            super.onPostExecute(result);
            listener.onTaskCompleted(result);
    
        }
    
    }
    

    ServiceHanlder.java

    public class ServiceHandler {
    
        static String response = null;
        public final static int GET = 1;
        public final static int POST = 2;
    
    
        public ServiceHandler() {
    
        }
    
        /**
         * Making service call
         *
         * @url - url to make request
         * @method - http request method
         */
        public static String makeServiceCall(String url, int method) {
            return makeServiceCall(url, method, null);
        }
    
        /**
         * Making service call
         *
         * @url - url to make request
         * @method - http request method
         * @params - http request params
         */
        public static String makeServiceCall(String url, int method,
                                      List<NameValuePair> params) {
            try {
                // http client
                DefaultHttpClient httpClient = new DefaultHttpClient();
                HttpEntity httpEntity = null;
                HttpResponse httpResponse = null;
    
                // Checking http request method type
                if (method == POST) {
                    HttpPost httpPost = new HttpPost(url);
                    // adding post params
                    if (params != null) {
                        httpPost.setEntity(new UrlEncodedFormEntity(params));
                    }
                    Log.e("Selltis Request URL", url);
                    httpResponse = httpClient.execute(httpPost);
    
                } else if (method == GET) {
                    // appending params to url
                    if (params != null) {
                        String paramString = URLEncodedUtils
                                .format(params, "utf-8");
                        url += paramString;
    
                        Log.i("Request URL", url);
                    }
                    HttpGet httpGet = new HttpGet(url);
    
                    httpResponse = httpClient.execute(httpGet);
    
                }
                httpEntity = httpResponse.getEntity();
                response = EntityUtils.toString(httpEntity);
    
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
                return "Fail";
            } catch (ClientProtocolException e) {
                e.printStackTrace();
                return "Fail";
            } catch (IOException e) {
                e.printStackTrace();
                return "Fail";
            }
    
            return response;
    
        }
    
    
    }
    

    Interface for Load More

    public interface OnLoadMoreListener {
         void onLoadMore();
    }
    

    Interface to know web service data loaded from asynctask

    public interface OnTaskCompleted{
    
        void onTaskCompleted(String response);
    }
    

    Please let me know if this works or any issues for you. Better to use Volley or okHttp Libraries for Networking.

    For ImageLoading i used Glide Library.