69

I'm using RecyclerView inside NestedScrollView. Also i set setNestedScrollingEnabled to false for recyclerview

to support lower API

ViewCompat.setNestedScrollingEnabled(mRecyclerView, false);

Now! When user scrolled the view every thing seems okay, but!!! views in recyclerview does not recycled!!! and Heap size grows swiftly!!

Update: RecyclerView layout manager is StaggeredLayoutManager

fragment_profile.xml:

<android.support.design.widget.CoordinatorLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/coordinator"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

        <android.support.design.widget.AppBarLayout
            android:id="@+id/appbar"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" >
        </android.support.design.widget.AppBarLayout>

        <android.support.v4.widget.SwipeRefreshLayout
            android:id="@+id/profileSwipeRefreshLayout"
            android:layout_width="match_parent"
            android:layout_height="match_parent" >

                <!-- RecyclerView and NestedScrollView -->
                <include layout="@layout/fragment_profile_details" />

        </android.support.v4.widget.SwipeRefreshLayout>

</android.support.design.widget.CoordinatorLayout>

fragment_profile_details.xml:

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/rootLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"
    android:orientation="vertical" >

        <android.support.v4.widget.NestedScrollView
            android:id="@+id/nested_scrollbar"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_gravity="fill_vertical"
            app:layout_behavior="@string/appbar_scrolling_view_behavior"
            android:fillViewport="true"
            android:scrollbars="none" >

                <LinearLayout
                    android:id="@+id/nested_scrollbar_linear"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:descendantFocusability="blocksDescendants"
                    android:orientation="vertical" >

                        <android.support.v7.widget.CardView
                            android:id="@+id/profileCardview"
                            android:layout_width="match_parent"
                            android:layout_height="wrap_content"
                            app:cardBackgroundColor="@color/card_backgroind"
                            app:cardCornerRadius="0dp"
                            app:cardElevation="0dp" >

                            <!-- Profile related stuff like avatar and etc. --->

                        </android.support.v7.widget.CardView>

                        <android.support.v7.widget.RecyclerView
                            android:id="@+id/list_view"
                            android:layout_width="match_parent"
                            android:layout_height="wrap_content"
                            android:layout_marginBottom="@dimen/four"
                            android:layout_marginEnd="@dimen/four"
                            android:layout_marginLeft="@dimen/four"
                            android:layout_marginRight="@dimen/four"
                            android:layout_marginStart="@dimen/four"
                            android:layout_marginTop="@dimen/four"
                            app:layout_behavior="@string/appbar_scrolling_view_behavior"
                            android:clipToPadding="false" />

                </LinearLayout>
        </android.support.v4.widget.NestedScrollView>
</LinearLayout>

ProfileFragment.java:

mAdapter        = new MainAdapter(getActivity(), glide, Data);

listView        = (RecyclerView) view.findViewById(R.id.list_view);

ViewCompat.setNestedScrollingEnabled(listView, false);  
listView.setAdapter(mAdapter);

mStaggeredLM    = new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL);
mStaggeredLM.setGapStrategy(StaggeredGridLayoutManager.GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS);

listView.setLayoutManager(mStaggeredLM);

mScroll.setOnScrollChangeListener(new OnScrollChangeListener() {

        @Override
        public void onScrollChange(NestedScrollView arg0, int arg1, int arg2, int arg3, int arg4) {

            View view   = (View) mScroll.getChildAt(mScroll.getChildCount() - 1);
            int diff    = (view.getBottom() - ( mScroll.getHeight() + mScroll.getScrollY()));

            if(diff == 0){

                int visibleItemCount            = mStaggeredLM.getChildCount();
                int totalItemCount              = mStaggeredLM.getItemCount();

                int[] lastVisibleItemPositions  = mStaggeredLM.findLastVisibleItemPositions(null);
                int lastVisibleItemPos  = getLastVisibleItem(lastVisibleItemPositions);

                Log.e("getChildCount", String.valueOf(visibleItemCount));
                Log.e("getItemCount", String.valueOf(totalItemCount));
                Log.e("lastVisibleItemPos", String.valueOf(lastVisibleItemPos));

                if ((visibleItemCount + 5) >= totalItemCount) {

                    mLoadMore.setVisibility(View.VISIBLE);
                    Log.e("LOG", "Last Item Reached!");
                }

                mMore = true;
                mFresh = false;
                mRefresh = false;
                getPosts();
            }

        }

    });

P.s : I've set load more to scroll view, because recyclerview do it continuously and none stoppable!

Any help is appreciated

MAY3AM
  • 1,182
  • 3
  • 17
  • 42
  • Can you explain the reason why did you add `RecyclerView` inside `NestedScrollView`? – romtsn Jun 05 '16 at 07:27
  • @rom4ek http://stackoverflow.com/questions/37437161/dealing-with-recyclerview-nestedscrollview-and-cardview – MAY3AM Jun 05 '16 at 08:17
  • @MAY3AM update your code and xml – appukrb Jun 07 '16 at 05:31
  • @appukrb done, code and xml was added – MAY3AM Jun 07 '16 at 06:13
  • what version of recyclerview you have compiled in your gradle? – Khairul Alam Licon Jun 09 '16 at 02:03
  • @MAY3AM have you tried solution suggested by Rehan for http://stackoverflow.com/questions/37437161/dealing-with-recyclerview-nestedscrollview-and-cardview ? – Pr38y Jun 09 '16 at 08:46
  • @Pr38y I don't want update my adapter – MAY3AM Jun 09 '16 at 10:14
  • 14
    `NestedScrollView` draws all child element, So if `RecyclerView` has been used inside `NestedScrollView` all the element of adapter will be loaded at first time itself. A better approach will be to use `RecyclerView` only and use `getItmeViewType` to return `cardView` `if(position==0)` in `adapter`. as suggested by Rehan. – Pr38y Jun 09 '16 at 10:21
  • @Pr38y I've tried this before and I got some performance issue, this approach could be okay when using `LinearLayoutManager` but in my case with `StaggeredGridLayoutManager`, it could not help so. – MAY3AM Jun 09 '16 at 10:35
  • 2
    I normally go with @Pr38y. what performance issue are you facing? – Tin Tran Jun 11 '16 at 09:34
  • Side note: don’t use `ViewCompat` , use `RecyclerView#setNestedScrollingEnabled`. RecyclerView comes from support libraries and is already backporting its functionality to older APIs. – natario Jun 12 '16 at 21:40
  • @MAY3AM did you find a solution? – Kevin Robatel Jul 25 '16 at 14:50
  • @Kevinrob Nope yet!! :( – MAY3AM Jul 25 '16 at 20:10
  • Hi @MAY3AM. Got any solution? I have multiple horizontal scrolling RecyclerView's inside NestedScrollView. Have added- setNestedScrollingEnabled(true) and facing the same issue (recyclerview is not recycling) – Wijay Sharma Jan 03 '18 at 05:47
  • @WijaySharma Hi there, unfortunately, I've got nothing :( – MAY3AM Jan 13 '18 at 05:00

2 Answers2

10

This is because we have a recycler view which has scroll behaviour inside a scroll view. (scroll inside a scroll)

I think the best way to resolve this issue is to your profileCardview as a header in your recycler view and then remove the nested scroll view.

If it were a listview then it was as simple as listView.addHeaderView(profileCardView) but for the Recycler view there is no addheadview equivalent. Hence you could refer the below link to change your implementation.

Is there an addHeaderView equivalent for RecyclerView?

Community
  • 1
  • 1
Arpit Ratan
  • 2,976
  • 1
  • 12
  • 20
  • What if the requirement of the design team is more complex than this? In my case, the "header" has a TabLayout (and some simple views above), and needs to be scrolled nicely so that the TabLayout alone would stay at the top of the screen when scrolling. Below the TabLayout, there is a ViewPager of 2 RecyclerViews as pages (belong to the TabLayout so it has 2 tabs). In this case, there is no single RecyclerView, and I'm not sure how to have the scrolling stop (pin at the top) for some Views of the RecyclerView even if I had just one. – android developer Jul 06 '23 at 07:47
4

For a RecyclerView or ListView the height should be constant, because if it will not a constant size then how it will manage the maximum number of visible rows in memory. Try by changing RecyclerView attribute android:layout_height="match_parent" or a fixed height(e.g. "300dp" - as needed), instead of "wrap_content". It should improve your memory management.

Neo
  • 3,546
  • 1
  • 24
  • 31
  • 3
    @CliveJefferies Setting layout_height to a fixed size will reduce re-drawing when a sub-view is updated. You are kind of saying "don't worry - no need to re-draw this view if my subviews change because it has a fixed size". You could, in theory, say that it might reduce memory footprints, but mainly it will eliminate UI-blocking garbage collections which will make your app smoother. – Arturs Vancans Mar 08 '19 at 13:52
  • But what happens if all is supposed to scroll, so that some part above the RecyclerView should pin ? Would you need to keep setting the height of the RecyclerView based on scrolling listener ? – android developer Jul 06 '23 at 07:49