Mohamed AbdelraZek
Mohamed AbdelraZek

Reputation: 2809

Android RecyclerView doesn't recycle items

I have A recyclerView that have multiple recyclerView with a dynamic inflation, the response I

am getting from the server is a list that contains objects each one contains a list and attributes for the

recyclerView type (Vertical or Horizontal) LinearLayout.

everything works fine except that when the orienatation is Vertical the adapter wait to load all Views at once (stop recycling).

I have searched a lot to find a solution but nothing.

the Main RecyclerView inside HomeFragment

<androidx.constraintlayout.widget.ConstraintLayout 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:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.gt.gcook.ui.home.HomeFragment">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recyclerView"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:orientation="vertical"
        android:nestedScrollingEnabled="false"
        app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        tools:listitem="@layout/home_single_item" />
</androidx.constraintlayout.widget.ConstraintLayout>

home_single_item layout (contains of 2 TextView and RecyclerView)

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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:layout_width="match_parent"
    android:layout_height="wrap_content">

    <TextView
        android:id="@+id/seeAllTV"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="32dp"
        android:layout_marginEnd="24dp"
        android:text="See all"
        android:textColor="@color/color_yellow"
        android:textSize="16sp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/titleTV"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="24dp"
        android:layout_marginTop="32dp"
        android:text="Catigories"
        android:textColor="#707070"
        android:textSize="22sp"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recyclerView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="24dp"
        android:nestedScrollingEnabled="false"
        app:reverseLayout="false"
        android:clipToPadding="false"
        app:layoutManager="androidx.recyclerview.widget.GridLayoutManager"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/titleTV" />

</androidx.constraintlayout.widget.ConstraintLayout>

onBindViewHolder of Home RecyclerView .

override fun onBindViewHolder(holder: ViewHolder, position: Int) {
    when (position) {
        0 -> {
            holder.itemView.titleTV.text = "Categories"
            val mLayoutManager = LinearLayoutManager(holder.itemView.context)
            mLayoutManager.orientation = RecyclerView.HORIZONTAL
            holder.itemView.recyclerView.layoutManager = mLayoutManager
            holder.itemView.recyclerView.adapter = HomeCategoryAdapter()


        }
        1 -> { //here is the problem when Orintation is vertical.
            holder.itemView.titleTV.text = "Most rated recipes"
            val mLayoutManager = GridLayoutManager(holder.itemView.context, 2)
            mLayoutManager.orientation = RecyclerView.VERTICAL
            holder.itemView.recyclerView.layoutManager = mLayoutManager
            holder.itemView.recyclerView.adapter = MostRatedRecipeAdapter(clickListener)


        }
        else -> {
            holder.itemView.titleTV.text = "Favourite"
            val mLayoutManager = LinearLayoutManager(holder.itemView.context)
            mLayoutManager.orientation = RecyclerView.HORIZONTAL
            holder.itemView.recyclerView.layoutManager = mLayoutManager
            holder.itemView.recyclerView.adapter = HomeCategoryAdapter()
        }
    }
}

Upvotes: 4

Views: 1756

Answers (1)

Rinat Diushenov
Rinat Diushenov

Reputation: 1245

Since your inner RV's height is set to wrap_content there is no way to enable recycling for that case. When its horizontal, recycling is working because it's width is match_parent and screen width is fixed. Recycling works only when there is defined height!

However, as i said there is room for optimization:

Right now, you are creating adapter for inner RV inside parent RV's onBindViewHolder() method, thus forcing inner RV to inflate ViewHolders every time parent RV decides to reuse it's previous ViewHolders via rebinding new values.

You can create adapters for inner RV inside onCreateVoewHolder() of parent RV and submit new list to inner adapter ( subsequently calling notifyDatasetChanged() ) inside OnBindViewHolder().

The above approach should certainly improve performance, at least on subsequent scrolling: recycling will work on parent RV scroll, meaning inner RV will retain its ViewHolders and reuse them to some degree.

Unfortunately, i don't have time to post snippet precisely for your scenario but you can have a look at my another answer: Show values of same key in one TextView in Recyclerview

Upvotes: 5

Related Questions