Search code examples
androidandroid-viewpagerandroid-recyclerviewlinearlayoutmanager

Android RecyclerView plus ViewPager


I have a ViewPager that utilizes a RecyclerView for each page and shares ViewItem rows across pages. Accordingly I share a single RecyclerViewPool between them. However, the ViewPager loads each RecyclerView whether or not it is the page on screen. Is there a way to indicate to the RecyclerView that all of its items are offscreen and force its views to be returned to the Recycler?

My sense is that subclassing LinearLayoutManager and overriding its onLayoutChildren method is the way to go, but I don't have much experience with LayoutManager and would like some guidance.


Solution

  • So here is a subclass of LinearLayoutManager that operates the way I described:

    public class PageVisibleLinearLayoutManager extends LinearLayoutManager {
        public PageVisibleLinearLayoutManager(Context context) {
            super(context);
        }
    
        public PageVisibleLinearLayoutManager(Context context, int orientation, boolean reverseLayout) {
            super(context, orientation, reverseLayout);
        }
    
        public PageVisibleLinearLayoutManager(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
            super(context, attrs, defStyleAttr, defStyleRes);
        }
    
        private boolean pageVisible = true;
    
        void setPageVisible(boolean pageVisible) {
            boolean change = (this.pageVisible != pageVisible);
            this.pageVisible = pageVisible;
            if(change) requestLayout();
        }
    
        @Override
        public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
            if(pageVisible) {
                super.onLayoutChildren(recycler, state);
            } else {
                removeAndRecycleAllViews(recycler);
            }
        }
    }
    

    It works nicely and gives up its views if requested. As dsh mentioned, it is important to mark adjacent pages as being on screen (and I really don't know why setOffscreenPageLimit doesn't limit the number of pages loaded as expected). My previous solution was to use ViewStub and inflate a page only when it was on screen or adjacent. The layout manager method is slightly faster upon initial turning to an unloaded page, but ViewStub has the advantage of pages staying in memory once loaded (making subsequent scrolling more smooth), so I decided to stick with that.

    Thank you all. Next question...