Prevent RecyclerView in BottomSheet from rendering offscreen views

Viewed 124

Reproducible sample project on github: recyclerview-bottomsheet-not-recycling

On Android it is common to have a draggable bottomsheet. For any scrollable content, RecyclerView is a great candidate. However, when put inside a bottomsheet, recycling/virtualization does not occur for the items that would have been visible if the bottomsheet was fully expanded. This implies a significant performance hit for no apparent reason. I.e. views are inflated and the onDraw() method is called. I believe tons of BottomSheet featured apps silently suffer from this. There ought to be a solution to this non-performant behavior.

Google issue exists: https://issuetracker.google.com/issues/180537056

How can you configure/tweak RecyclerView or its LayoutManager to prevent invisible bottomsheet items from being rendered? Please avoid ViewStub solutions. Let's focus on the root of the problem - the RecyclerView.

Illustration

E.g. If the height of the main layout is 1000px and the invisible RecyclerView has items with a height of 200px, then five views will be immediately created and rendered:

My App


Main View (1000px)


Collapsed bottom sheet
Item 1 rendered
Item 2 rendered
Item 3 rendered
Item 4 rendered
Item 5 rendered
Item 6 NOT rendered
Item 7 NOT rendered
...

And a screenshot from the sample app on github. Here a bunch of items below the screen have been rendered - even though they are invisible.

Sample app

The relevant part of the layout

<androidx.coordinatorlayout.widget.CoordinatorLayout
   android:id="@+id/layout_retainer"
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   android:background="@android:color/black">

   <androidx.recyclerview.widget.RecyclerView
       android:id="@+id/bottom_sheet"
       android:layout_width="match_parent"
       android:layout_height="match_parent"
       android:paddingBottom="@dimen/activity_vertical_margin"
       android:clipToPadding="false"
       android:background="@color/white"
       app:behavior_hideable="false"
       app:behavior_peekHeight="@dimen/bottom_sheet_peek_height"
       app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior"
       android:adapter="@{adapter}" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
0 Answers
Related