1

Hello I need to make the infinite scrolling (Pagination) with the recyclerview using the staggeredGridLayoutManager. Pagination is working but the problem is that onLoadMore() function is called so many times while scrolling which causing problems, here is my code:

 newSearchAdapter = new NewSearchAdapter(getActivity(), gridData);
            StaggeredGridLayoutManager mLayoutManager;
            mLayoutManager = new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL);
            mLayoutManager.setGapStrategy(StaggeredGridLayoutManager.GAP_HANDLING_NONE);
            rv_NewProfilesGrid.setLayoutManager(mLayoutManager);
            rv_NewProfilesGrid.setAdapter(newSearchAdapter);
            rv_NewProfilesGrid.addOnScrollListener(new EndlessRecyclerOnScrollListenerStaggeredLayoutmanager(mLayoutManager) {
                @Override
                public void onLoadMore(int current_page) {

                  //calling the api

                }
            });

and here is my scroll listner

I think the problem here is with the getFirstVisibleItems() function because with GridLayoutManger or LinearLayoutManager it returns an integer but with StaggeredLayout it returns an int Array, so I did the following:

public abstract class EndlessRecyclerOnScrollListenerStaggeredLayoutmanager extends RecyclerView.OnScrollListener {
    public static String TAG = EndlessRecyclerOnScrollListenerStaggeredLayoutmanager.class.getSimpleName();
    private int scrolledDistance = 0;
    private boolean controlsVisible = false;

    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.
    public static boolean  loadOneTime = false;
    private int pastVisibleItems, visibleItemCount, totalItemCount,previousTotal;

    private int current_page = 1;

    private StaggeredGridLayoutManager mStaggeredGridLayoutManager;

    public EndlessRecyclerOnScrollListenerStaggeredLayoutmanager(StaggeredGridLayoutManager staggeredGridLayoutManager) {
        this.mStaggeredGridLayoutManager = staggeredGridLayoutManager;

    }


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

        visibleItemCount = recyclerView.getChildCount();
        totalItemCount = mStaggeredGridLayoutManager.getItemCount();

        int[] firstVisibleItems = null;
        firstVisibleItems = mStaggeredGridLayoutManager.findFirstVisibleItemPositions(firstVisibleItems);
        if (firstVisibleItems != null && firstVisibleItems.length > 0) {
            pastVisibleItems = firstVisibleItems[0];
        }


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

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

            // Do something
            current_page++;
            loadOneTime=false;
            onLoadMore(current_page);

            loading = true;
        }

        if (scrolledDistance > 1 && controlsVisible) {
            controlsVisible = false;
            scrolledDistance = 0;
        } else if (scrolledDistance < -1 && !controlsVisible) {
            controlsVisible = true;
            scrolledDistance = 0;
        }

        if ((controlsVisible && dy > 0) || (!controlsVisible && dy < 0)) {
            scrolledDistance += dy;
        }
    }

    public abstract void onLoadMore(int current_page);


}
Mulham Raee
  • 313
  • 1
  • 8
  • i am having the same problem but with the Paging library and came across this github gist https://gist.github.com/pratikbutani/dc6b963aa12200b3ad88aecd0d103872 i think it will solve your problem – medyas Dec 22 '18 at 18:29

1 Answers1

1

Try this. I borrowed it from a stack overflow answer and borrowed another answer and combine to of them I finally solve it.

import android.util.Log
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.StaggeredGridLayoutManager

abstract class PaginationScrollListener constructor() :
    RecyclerView.OnScrollListener() {

    private lateinit var mLayoutManager: RecyclerView.LayoutManager

    constructor(layoutManager: GridLayoutManager) : this() {
        this.mLayoutManager = layoutManager
    }

    constructor(layoutManager: StaggeredGridLayoutManager) : this() {
        this.mLayoutManager = layoutManager
    }

    constructor(layoutManager: LinearLayoutManager) : this() {
        this.mLayoutManager = layoutManager
    }


    /*
     Method gets callback when user scroll the search list
     */
    override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
        super.onScrolled(recyclerView, dx, dy)

        val visibleItemCount = mLayoutManager.childCount
        val totalItemCount = mLayoutManager.itemCount
        var firstVisibleItemPosition = 0

        when (mLayoutManager) {
            is StaggeredGridLayoutManager -> {
                val firstVisibleItemPositions =
                    (mLayoutManager as StaggeredGridLayoutManager).findFirstVisibleItemPositions(null)
                // get maximum element within the list
                firstVisibleItemPosition = firstVisibleItemPositions[0]
            }
            is GridLayoutManager -> {
                firstVisibleItemPosition =
                    (mLayoutManager as GridLayoutManager).findFirstVisibleItemPosition()
            }
            is LinearLayoutManager -> {
                firstVisibleItemPosition =
                    (mLayoutManager as LinearLayoutManager).findFirstVisibleItemPosition()
            }
        }
        if (!isLoading && !isLastPage) {
            if (visibleItemCount + firstVisibleItemPosition >= totalItemCount
                && firstVisibleItemPosition >= 0
            ) {
                Log.i(TAG, "Loading more items")
                loadMoreItems()
            }
        }
    }

    protected abstract fun loadMoreItems()

    abstract val isLastPage: Boolean
    abstract val isLoading: Boolean

    companion object {
        private val TAG = PaginationScrollListener::class.java.simpleName
    }
}

And use this in your recycler view in this way

rvCategoryProducts.addOnScrollListener(object :
            PaginationScrollListener(layoutManager) {
            override fun loadMoreItems() {
                vm.isLoading = true
                vm.currentPage++

                GlobalScope.launch {
                    vm.getCategoryProductByCatId(vm.id, vm.currentPage)
                }
            }

            override val isLastPage: Boolean
                get() = vm.isLastPage
            override val isLoading: Boolean
                get() = vm.isLoading
        })
Shaon
  • 2,496
  • 26
  • 27