1

I'm trying to create Recyclerview onLoadMore with ProgressBar at the bottom. I've tried this solution, but method onLoadMore in my Activity is never called. Please, help me.

Here is my Adapter:

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

    private ArrayList<NewsDataModel> dataSet;
    private Context context;

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

    // 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 NewsAdapterTest(ArrayList<NewsDataModel> data, Context context, RecyclerView recyclerView) {
        this.dataSet = data;
        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)) {
                        // End has been reached
                        // Do something
                        Log.i("newsAdaptertest", "onScrolled: End reached");
                        if (onLoadMoreListener != null) {
                            onLoadMoreListener.onLoadMore();
                        }
                        loading = true;
                    }
                }
            });
        }

    }

    public class MyViewHolder extends RecyclerView.ViewHolder {
        ExpandableTextView postMessage;
        TextView postTitle;
        TextView postSubTitle;
        ImageView authorImage;

        public MyViewHolder(View itemView) {
            super(itemView);
            this.authorImage = (ImageView) itemView.findViewById(R.id.header_image);
            this.postTitle = (TextView) itemView.findViewById(R.id.header_title);
            this.postSubTitle = (TextView) itemView.findViewById(R.id.header_subtitle);
            this.postMessage = (ExpandableTextView) itemView.findViewById(R.id.post_text_expand);
        }
    }

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

    @Override
    public int getItemViewType(int position) {
        return dataSet.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.recycler_news, parent, false);

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

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

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int listPosition) {
        if (holder instanceof MyViewHolder) {
            Binding Views...
        } else {
            ((ProgressViewHolder) holder).progressBar.setIndeterminate(true);
        }
    }

    public void setLoaded() {
        loading = false;
    }

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

    public interface OnLoadMoreListener {
        void onLoadMore();
    }

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

        public ProgressViewHolder(View v) {
            super(v);
            progressBar = (ProgressBar) v.findViewById(R.id.progressBar);
        }
    }

}

And my Activity:

private static NewsAdapterTest adapter;
    private LinearLayoutManager layoutManager;
    private static RecyclerView recyclerView;
    private ArrayList<NewsDataModel> data = new ArrayList<NewsDataModel>();

recyclerView = (RecyclerView) findViewById(R.id.recyclerview_news);
        layoutManager = new LinearLayoutManager(this);
        adapter = new NewsAdapterTest(data, NewsActivity.this, recyclerView);

        recyclerView.setHasFixedSize(false);
        recyclerView.setLayoutManager(layoutManager);
        recyclerView.setItemAnimator(new DefaultItemAnimator());

        adapter.setOnLoadMoreListener(new NewsAdapterTest.OnLoadMoreListener() {
            @Override
            public void onLoadMore() {
                Log.i(TAG, "onLoadMore called");
                //add progress item
                data.add(null);
                adapter.notifyItemInserted(data.size() - 1);

                Log.i(TAG, "Loading new data... (" + Integer.toString(loadNumber) + ") posts");
                loadPosts(startLoadPosition, loadNumber);
                startLoadPosition += loadNumber;

                //remove progress item
                data.remove(data.size() - 1);
                adapter.notifyItemRemoved(data.size());
                //add items one by one

                adapter.setLoaded();
                //or you can add all at once but do not forget to call mAdapter.notifyDataSetChanged();
            }
        });
Community
  • 1
  • 1
Roman Svyatnenko
  • 609
  • 11
  • 26

1 Answers1

3

Sample Code:

MainActivity:

package com.example.sabari.recyclerviewsample;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;

import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {

    private static RecyclerViewAdapter adapter;
    private LinearLayoutManager layoutManager;
    private static RecyclerView recyclerView;
    private List<Book> data = new ArrayList<>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        getNextItems();
        recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
        layoutManager = new LinearLayoutManager(this);
        recyclerView.setHasFixedSize(false);
        recyclerView.setLayoutManager(layoutManager);
        adapter = new RecyclerViewAdapter(data, this, recyclerView);
        recyclerView.setAdapter(adapter);
        recyclerView.setItemAnimator(new DefaultItemAnimator());

        adapter.setOnLoadMoreListener(new RecyclerViewAdapter.OnLoadMoreListener() {
            @Override
            public void onLoadMore() {
                Log.i("LoadMore", "onLoadMore called");
                //add progress item
                data.add(null);
                adapter.notifyDataSetChanged();

                Log.i("LoadMore", "Loading new data... (" + 5 + ") posts");
                //remove progress item
                data.remove(data.size() - 1);

                getNextItems();

                adapter.notifyDataSetChanged();
                //add items one by one

                adapter.setLoaded();
            }
        });

    }

    private void getNextItems() {
        int itemCount = data.size();
        for (int i = itemCount; i <= itemCount + 5; i++) {
            Book book = new Book();
            book.title = "Title " + i;
            book.author = "Author " + i;
            book.description = "Description " + i;
            book.imageId = R.drawable.empty_user;
            data.add(book);
        }
    }

}

RecyclerViewAdapter:

package com.example.sabari.recyclerviewsample;

import android.content.Context;
import android.support.v4.content.ContextCompat;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;

import java.util.List;

/**
 * Created by sabari on 2/8/2016.
 */
public class RecyclerViewAdapter extends RecyclerView.Adapter {
    private List<Book> dataSet;
    private Context context;

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

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

    public RecyclerViewAdapter(List<Book> data, Context context, RecyclerView recyclerView) {
        this.dataSet = data;
        this.context = context;

        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);
                final LinearLayoutManager linearLayoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
                totalItemCount = linearLayoutManager.getItemCount();
                lastVisibleItem = linearLayoutManager.findLastVisibleItemPosition();
                if (!loading && totalItemCount <= (lastVisibleItem + visibleThreshold)) {
                    loading = true;
                    // End has been reached
                    // Do something
                    Log.i("AdapterScrolled", "onScrolled: End reached");
                    if (onLoadMoreListener != null) {
                        onLoadMoreListener.onLoadMore();
                    }

                }
            }
        });

    }

    public class MyViewHolder extends RecyclerView.ViewHolder {
        TextView description;
        TextView title;
        TextView author;
        ImageView profilePic;

        public MyViewHolder(View itemView) {
            super(itemView);
            this.profilePic = (ImageView) itemView.findViewById(R.id.user_profile_pic);
            this.title = (TextView) itemView.findViewById(R.id.title);
            this.author = (TextView) itemView.findViewById(R.id.author);
            this.description = (TextView) itemView.findViewById(R.id.description);
        }
    }

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

    @Override
    public int getItemViewType(int position) {
        return dataSet.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.book_layout, parent, false);

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

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

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        if (holder instanceof MyViewHolder) {
//                Binding Views...
            Book book = dataSet.get(position);
            ((MyViewHolder) holder).profilePic.setImageDrawable(ContextCompat.getDrawable(context, book.imageId));
            ((MyViewHolder) holder).title.setText(book.title);
            ((MyViewHolder) holder).author.setText(book.author);
            ((MyViewHolder) holder).description.setText(book.description);
        } else {
            ((ProgressViewHolder) holder).progressBar.setIndeterminate(true);
        }
    }

    public void setLoaded() {
        loading = false;
    }

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

    public interface OnLoadMoreListener {
        void onLoadMore();
    }

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

        public ProgressViewHolder(View v) {
            super(v);
            progressBar = (ProgressBar) v.findViewById(R.id.progressBar);
        }
    }
}
Sabari
  • 1,853
  • 1
  • 11
  • 10
  • I load 5 items per time. So, when my `Activity` opens, I have only 5 items, I can scroll down, but `RecyclerView` doesn't call `onLoadMore`. – Roman Svyatnenko Feb 07 '16 at 13:58
  • In NewAdapterTest-> onScrolled event replace "if (!loading && totalItemCount <= (lastVisibleItem + visibleThreshold))" to "if(!loading)" try this – Sabari Feb 07 '16 at 14:16
  • If above condition(previous message) is working, I hope "totalItemCount <= (lastVisibleItem + visibleThreshold)" this condition returning false. Make sure it. – Sabari Feb 07 '16 at 14:38
  • Still not loading. I don't know why, but Adapter in onCreateViewHolder gets only 1(MyViewHolder), so I think adapter in Activity doesn't do this `data.add(null);` – Roman Svyatnenko Feb 07 '16 at 14:40
  • Now I got it. Create a method in NewAdapterTest, public void setData(list data) { this.dataSet = data; } – Sabari Feb 07 '16 at 14:51
  • If data list updated, call setData method and update the adapter data list. This should happen before calling adapter.notifyiteminserted/ adapter.notifyitemremoved – Sabari Feb 07 '16 at 14:55
  • Problem is, you are updating local data list, not the data list in adaptor. – Sabari Feb 07 '16 at 14:57
  • Finally! I found problem. I called `adapter = new NewsAdapterTest(data, NewsActivity.this, recyclerView);` before setting up `RecyclerView`... – Roman Svyatnenko Feb 07 '16 at 15:29
  • But have new one... `adapter.setLoaded();` is never called. – Roman Svyatnenko Feb 07 '16 at 15:37
  • I have uploaded a sample code. In your case, In NewAdapterTest => OnScrolled event, call this " loading = true;" before " if (onLoadMoreListener != null) { onLoadMoreListener.onLoadMore(); }" – Sabari Feb 08 '16 at 10:13
  • Thank you very much! Data loads fine, but I don't see `ProgressBar`. `data.add(null); adapter.notifyItemInserted(data.size() - 1);` is called, but there is no `ProgressBar` – Roman Svyatnenko Feb 08 '16 at 14:29
  • Replace " data.remove(data.size() - 1);adapter.notifyItemRemoved(data.size()); " with this "adapter.notifyDataSetChanged();" and check it, progress bar is visible or not. – Sabari Feb 08 '16 at 15:15
  • The problem was in `AsyncTask`, which I use for data loading. So, everything works excellent. Thank you very very much, @Sabari! – Roman Svyatnenko Feb 08 '16 at 15:24