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.
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>
