1

I have two RecyclerViews in one layout. Until now I can't scroll the page itself, only each RecyclerView, which feels strange. Now I am trying to figure out the best practive for scrolling a page with two RecyclerViews. I heard that when I put them in a NestedScrollView, they stop recycling their views.

  1. Is is true that putting RecyclerView inside a NestedScrollView disables the recycling of items in the RecyclerView?
  2. Especially if number 1 is true, what is the current recommended way to enable scrolling for a page with two Recyclerviews?

Update Here's my layout. Assume that recycler1 and recycler2 don't carry items that are related together, so putting them inside one RecyclerView (using different view types) feels semantically wrong to me.

<androidx.constraintlayout.widget.ConstraintLayout
    android:id="@+id/layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/text1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginLeft="16dp"
        android:text="first title"
        app:layout_constraintBottom_toTopOf="@+id/recycler1"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />


    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recycler1"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginLeft="16dp"
        android:layout_marginEnd="16dp"
        android:layout_marginRight="16dp"
        android:orientation="vertical"
        app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/text1"
        tools:itemCount="3"
        tools:listitem="@layout/item_category" />

    <TextView
        android:id="@+id/text2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginLeft="16dp"
        android:layout_marginTop="24dp"
        android:text="second title"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/recycler1" />

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recycler2"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginLeft="16dp"
        android:layout_marginEnd="16dp"
        android:layout_marginRight="16dp"
        android:orientation="vertical"
        app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/text2"
        tools:itemCount="3"
        tools:listitem="@layout/item_category" />

</androidx.constraintlayout.widget.ConstraintLayout>
stefan.at.kotlin
  • 15,347
  • 38
  • 147
  • 270

2 Answers2

2

This is precisely the use case for ConcatAdapter as per the Concatenate adapters sequentially with ConcatAdapter blog post:

ConcatAdapter is a new class available in recyclerview:1.2.0-alpha02 which enables you to sequentially combine multiple adapters to be displayed in a single RecyclerView. This enables you to better encapsulate your adapters rather than having to combine many data sources into a single adapter, keeping them focused and re-usable.

This allows you to write your layout as a single RecyclerView that correctly recycles views while keeping each individual adapter (and their loading of data) separate.

In your case, you should consider actually having 4 adapters - two simple ones for your titles (or two instances of the same TitleAdapter you could write), plus one for each of your previous adapters.

Then you'd construct your ConcatAdapter by passing all 4 adapters in to make one scrollable RecyclerView:

val firstTitleAdapter = TitleAdapter("first title")
val firstListAdapter: FirstListAdapter = …

val secondTitleAdapter = TitleAdapter("second title")
val secondListAdapter: SecondListAdapter = …

val concatAdapter = ConcatAdapter(firstTitleAdapter, firstListAdapter, 
   secondTitleAdapter, secondListAdapter)
recyclerView.adapter = concatAdapter
stefan.at.kotlin
  • 15,347
  • 38
  • 147
  • 270
ianhanniballake
  • 191,609
  • 30
  • 470
  • 443
  • great, thank you. Just implemented that successfully and it just works for my case :-) – stefan.at.kotlin Aug 08 '20 at 13:38
  • @ianhanniballake if I have a SearchView in the adapter item at the very top of the recyclerview, then how do I prevent it from recycling when scolling down and then back up again? Since I am passing the open and close value of this SearchView via the setOnSearchListener and setOnCloseListener to the ViewModel so that it can use it to update a MutableStateFlow and then I use a flatmapLatest on this MutableStateFlow to switch between the list that was originally fetched and the one that contains the search results. Then I collect this final list in my View. Any help will be appreciated thanks :) – mehul bisht Jun 27 '21 at 01:25
0

NestedScrollView - indeed does the thing. The whole point of NestedScrollView is that it calculates the whole recycler view size with all its children To do it it needs to render all the children of the list - thus indeed Android paradoxically will not be able to RecycleViews in the RecyclerView. It is ok for small lists without pagination, but for huge lists it is a major performance issue.

The solution for that problem lies in the area of design(or program design). Instead of using two RecyclerView's use one with two view types. The second way out of this - divide your screen with two lists to two screens with one list each.

Generally having two lists one after another that need to scroll in conjunction with each other is bad design - so try to avoid such solutions.

Hope it helps.

Pavlo Ostasha
  • 14,527
  • 11
  • 35
  • thank you! not the answer that I hoped to read, but well explained. Guess I will eventually make a sectioned recycler view and select this answer as the correct one, if nothing else comes up :-) – stefan.at.kotlin Aug 05 '20 at 19:07
  • @stefan.at.wpf sections approach for recycler view is quite outdated one - use delegates approach or even use bindingadapter if you are using MVVM and view data binding. – Pavlo Ostasha Aug 06 '20 at 10:18
  • With Google I found something about the delegate approach (https://medium.com/@seidalins/delegate-adapters-building-heterogeneous-recyclerviewadapter-877cb7d3c6c0). I am not sure about the bindingadapter thing though. Can you provide more information on this? I don't get it how databinding relates to multiple view types. Thank you! – stefan.at.kotlin Aug 06 '20 at 16:11