title: Nested Recyclerview makes scroll laggy
body: <p>I am using recyclerview with multi view type and using nested recyclerviews:</p>
  <p><a href="https://i.stack.imgur.com/Qg7Q2.gif" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/Qg7Q2.gif" alt="enter image description here" /></a></p>
  <p>But its scrolling very slow. I also handled the child recyclerviews scroll position in onViewRecycled function:</p>
  <pre><code>override fun onViewRecycled(holder: RecyclerView.ViewHolder) {
      super.onViewRecycled(holder)
      //save horizontal scroll state
      val key = getSectionID(holder.layoutPosition)
  
      if (holder is HomeSectionsViewHolder) {
          scrollStates[key] =
              holder
                  .itemView
                  .findViewById&lt;RecyclerView&gt;(R.id.itemsList)
                  .layoutManager?.onSaveInstanceState()
      }
  }
  </code></pre>
  <p>And in the onBindViewHolder</p>
  <pre><code>val state = scrollStates[key]
          if (state != null) {
              itemBinding.itemsList.layoutManager?.onRestoreInstanceState(state)
          } else {
              itemBinding.itemsList.layoutManager?.scrollToPosition(0)
          }
  </code></pre>
  <p>I also tried:</p>
  <pre><code>binding.rvHome.recycledViewPool.setMaxRecycledViews(0, 0);
  </code></pre>
  <p>I am using ListAdapter with DiffUtils. I also tried to set adapter to child recyclerviews in the onCreateViewHolder and submit the list from onBindViewHolder and also tried setting adapter from onBindViewHolder. But in all cases main recycler view recycling the views and lagging. I dont want to disable the recycling of the recyclerview.</p>
  <p>Can anyone suggest me what i am doing wrong here.</p>
  <p><strong>Code:</strong></p>
  <pre><code>class MainAdapter(
      private val context: Context,
      private val currentLocale: String,
      private val currentCountry: String,
      private val homeRepository: HomeRepository
  ) :
      ListAdapter&lt;Section, RecyclerView.ViewHolder&gt;(Companion) {
  
      var selectedCondition: List&lt;Int?&gt;? = emptyList()
      var selectedBrand: MutableList&lt;Int?&gt;? = arrayListOf()
  
      private var carousalListBinded: Boolean = false
  
      private var carousalList: List&lt;CarouselItem&gt;? = null
      private var banners: List&lt;Banner&gt;? = null
  
      private var carousel: ImageCarousel? = null
      private var COVIDMsg: String? = null
      private var COVIDMsgColor: String? = null
      private var tvCovidMessage: TextView? = null
  
      private var categoryAdapter = CategoryAdapter(context)
  
  
  
      companion object : DiffUtil.ItemCallback&lt;Section&gt;() {
          override fun areItemsTheSame(oldItem: Section, newItem: Section): Boolean =
              oldItem == newItem
  
          override fun areContentsTheSame(oldItem: Section, newItem: Section): Boolean =
              oldItem == newItem
  
          const val VIEW_TYPE_CATEGORY = 0
          const val VIEW_TYPE_ITEM_SECTION = 1
          const val VIEW_TYPE_BRAND = 2
          const val VIEW_TYPE_IMAGE = 3
          const val VIEW_TYPE_ADVANCE_IMAGE = 4
          const val VIEW_TYPE_ADVANCE_CATEGORY = 5
          const val VIEW_TYPE_BANNER = 6
          const val VIEW_TYPE_HOME_BOTTOM_SECTION = 7
  
      }
  
      override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
          when (viewType) {
              VIEW_TYPE_CATEGORY -&gt; {
  
                  val categoryViewHolder = CategoryViewHolder(
                      DataBindingUtil.inflate(
                          LayoutInflater.from(parent.context),
                          R.layout.home_categories_item,
                          parent,
                          false
                      )
                  )
  
                  categoryViewHolder.initRecView()
  
                  return categoryViewHolder
  
              }
              VIEW_TYPE_ITEM_SECTION -&gt; {
  
                  val homeSectionsViewHolder = HomeSectionsViewHolder(
                      DataBindingUtil.inflate(
                          LayoutInflater.from(parent.context),
                          R.layout.home_item_section,
                          parent,
                          false
                      )
                  )
  
                  homeSectionsViewHolder.initRecView()
  
                  return homeSectionsViewHolder
              }
              VIEW_TYPE_BRAND -&gt; {
  
                  val brandsViewHolder = BrandsViewHolder(
                      DataBindingUtil.inflate(
                          LayoutInflater.from(parent.context),
                          R.layout.home_brands_item,
                          parent,
                          false
                      )
                  )
  
                  brandsViewHolder.initRecView()
  
                  return brandsViewHolder
              }
              VIEW_TYPE_IMAGE -&gt; {
  
                  val imagesViewHolder = ImagesViewHolder(
                      DataBindingUtil.inflate(
                          LayoutInflater.from(parent.context),
                          R.layout.home_brands_item,
                          parent,
                          false
                      )
                  )
  
                  imagesViewHolder.initRecView()
  
                  return imagesViewHolder
  
              }
              VIEW_TYPE_ADVANCE_IMAGE -&gt; {
  
                  val advanceImagesViewHolder = AdvanceImagesViewHolder(
                      DataBindingUtil.inflate(
                          LayoutInflater.from(parent.context),
                          R.layout.home_brands_item,
                          parent,
                          false
                      )
                  )
  
                  advanceImagesViewHolder.initRecView()
  
                  return advanceImagesViewHolder
              }
              VIEW_TYPE_ADVANCE_CATEGORY -&gt; {
  
                  val categorySectionViewHolder = CategorySectionViewHolder(
                      DataBindingUtil.inflate(
                          LayoutInflater.from(parent.context),
                          R.layout.home_item_section,
                          parent,
                          false
                      )
                  )
  
                  categorySectionViewHolder.initRecView()
  
                  return categorySectionViewHolder
  
              }
              VIEW_TYPE_BANNER -&gt; {
  
                  val binding: HomeBannerItemBinding = DataBindingUtil.inflate(
                      LayoutInflater.from(parent.context),
                      R.layout.home_banner_item,
                      parent,
                      false
                  )
  
  
                  binding.carousel.post {
                      val numberItemsInColumn = 1
                      val collectionViewWidth = getWidth(context)
                      val widthPerCell = collectionViewWidth / numberItemsInColumn
                      val widthPerItem = widthPerCell
                      val cellHeight = getCellHeight(widthPerItem)
  
                      binding.carousel.layoutParams.width = widthPerItem
                      binding.carousel.layoutParams.height = cellHeight
  
                      binding.carousel.requestLayout()
                  }
  
                  return HomeBannerViewHolder(
                      binding
                  )
  
              }
              VIEW_TYPE_HOME_BOTTOM_SECTION -&gt; {
                  return HomeBottomLayViewHolder(
                      DataBindingUtil.inflate(
                          LayoutInflater.from(parent.context),
                          R.layout.home_screen_bottom_layout,
                          parent,
                          false
                      )
                  )
              }
              else -&gt; {
  
                  val categoryViewHolder = CategoryViewHolder(
                      DataBindingUtil.inflate(
                          LayoutInflater.from(parent.context),
                          R.layout.home_categories_item,
                          parent,
                          false
                      )
                  )
  
                  categoryViewHolder.initRecView()
  
                  return categoryViewHolder
              }
          }
      }
  
      override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
          when (getItemViewType(position)) {
              VIEW_TYPE_CATEGORY -&gt; {
  
                  (holder as CategoryViewHolder).bind(position)
              }
              VIEW_TYPE_ITEM_SECTION -&gt; {
  
                  (holder as HomeSectionsViewHolder).bind(position)
  
              }
              VIEW_TYPE_BRAND -&gt; {
                  (holder as BrandsViewHolder).bind(position)
              }
  //
              VIEW_TYPE_IMAGE -&gt; {
                  (holder as ImagesViewHolder).bind(position)
              }
  //
              VIEW_TYPE_ADVANCE_IMAGE -&gt; {
                  (holder as AdvanceImagesViewHolder).bind(position)
              }
  
              VIEW_TYPE_ADVANCE_CATEGORY -&gt; {
                  (holder as CategorySectionViewHolder).bind(position)
              }
  
              VIEW_TYPE_BANNER -&gt; {
  //                (holder as HomeBannerViewHolder).setIsRecyclable(false)
                  (holder as HomeBannerViewHolder).bind()
              }
  
              VIEW_TYPE_HOME_BOTTOM_SECTION -&gt; {
                  (holder as HomeBottomLayViewHolder)
              }
          }
  
  //        holder.itemView.setFadeAnimation()
  
      }
  
      override fun getItemViewType(position: Int): Int {
  
          return when (currentList[position].sectionType) {
              SectionType.items -&gt; {
                  VIEW_TYPE_ITEM_SECTION
              }
              SectionType.brands -&gt; {
                  VIEW_TYPE_BRAND
              }
              SectionType.images -&gt; {
                  VIEW_TYPE_IMAGE
              }
              SectionType.advanceimages -&gt; {
                  VIEW_TYPE_ADVANCE_IMAGE
              }
              SectionType.category -&gt; {
                  VIEW_TYPE_ADVANCE_CATEGORY
              }
              SectionType.banners -&gt; {
                  VIEW_TYPE_BANNER
              }
              SectionType.homeCategories -&gt; {
                  VIEW_TYPE_CATEGORY
              }
              SectionType.homeBottomView -&gt; {
                  VIEW_TYPE_HOME_BOTTOM_SECTION
              }
              else -&gt; {
                  VIEW_TYPE_CATEGORY
              }
          }
  
      }
  
      inner class CategoryViewHolder(private val itemBinding: HomeCategoriesItemBinding) :
          RecyclerView.ViewHolder(
              itemBinding.root
          ) {
  
          fun initRecView() {
              itemBinding.rvCategoryItem.adapter = categoryAdapter
          }
  
          fun bind(position: Int) {
  
  //            val newItem = (currentList[position] as CategorySection).items
  //            categoryAdapter.submitList(newItem)
  
  
          }
      }
  
      inner class HomeSectionsViewHolder(private val itemBinding: HomeItemSectionBinding) :
          RecyclerView.ViewHolder(
              itemBinding.root
          ) {
  
          private var sectionsAdapter = ItemSectionsAdapter(context)
  
          fun initRecView() {
              itemBinding.itemsList.adapter = sectionsAdapter
          }
  
          fun bind(position: Int) {
  
              val section = getItem(position)
  
              itemBinding.section = section
              itemBinding.executePendingBindings()
  
              sectionsAdapter.submitList(null)
  
              val newItem = (currentList[position] as ItemSection).items
              sectionsAdapter.submitList(newItem)
  
  //            val state = scrollStates[key]
  //            if (state != null) {
  //                itemBinding.rvProducts.layoutManager?.onRestoreInstanceState(state)
  //            } else {
  //                itemBinding.rvProducts.layoutManager?.scrollToPosition(0)
  //            }
  
          }
  
      }
  
      inner class BrandsViewHolder(private val itemBinding: HomeBrandsItemBinding) :
          RecyclerView.ViewHolder(itemBinding.root) {
  
          private val brandsAdapter = BrandsAdapter()
  
          fun initRecView() {
              itemBinding.itemsList.adapter = brandsAdapter
          }
  
          fun bind(position: Int) {
  
              itemBinding.sectionBtnViewAll.visibility = View.INVISIBLE
  
              val section = getItem(position)
  
              itemBinding.section = section
              itemBinding.executePendingBindings()
  
              brandsAdapter.submitList((currentList[position] as BrandSection).items)
  
  
          }
  
      }
  
      inner class ImagesViewHolder(private val itemBinding: HomeBrandsItemBinding) :
          RecyclerView.ViewHolder(itemBinding.root) {
  
          private val imagesAdapter = ImagesAdapter(context)
          val layoutManager = GridLayoutManager(context, 3)
  
          fun initRecView() {
  
              itemBinding.itemsList.let {
  
                  it.layoutManager = layoutManager
  
                  it.setHasFixedSize(true)
                  it.adapter = imagesAdapter
              }
  
          }
  
          fun bind(position: Int) {
  
              val numberOfColumns = getNumberOfColumns((currentList[position] as ImageSection).items)
  
              itemBinding.itemsList.layoutManager = GridLayoutManager(context, numberOfColumns)
  
  //            layoutManager.spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() {
  //                override fun getSpanSize(position: Int): Int {
  //                    return numberOfColumns
  //                }
  //            }
  
              itemBinding.sectionBtnViewAll.visibility = View.INVISIBLE
  
              val section = getItem(position)
  
              itemBinding.section = section
              itemBinding.executePendingBindings()
  
  
              imagesAdapter.submitList((currentList[position] as ImageSection).items)
  
  
          }
  
  
      }
  
      inner class AdvanceImagesViewHolder(private val itemBinding: HomeBrandsItemBinding) :
          RecyclerView.ViewHolder(itemBinding.root) {
  
          private var imagesAdapter = AdvanceImagesAdapter(context, null, null)
  
          fun initRecView() {
  
              itemBinding.itemsList.let {
  
  //                val layoutManager = GridLayoutManager(context, getNumberOfColumns((currentList[position] as AdvanceImageSection).items))
                  val layoutManager = GridLayoutManager(context, 3)
  
                  it.layoutManager = layoutManager
  
                  it.setHasFixedSize(true)
                  it.adapter = imagesAdapter
              }
  
          }
  
          fun bind(position: Int) {
  
              val layoutManager = GridLayoutManager(
                  context,
                  getNumberOfColumns((currentList[position] as AdvanceImageSection).items)
              )
  
              itemBinding.itemsList.layoutManager = layoutManager
  
              val section = getItem(position)
  
  //            var imagesAdapter = AdvanceImagesAdapter(context, section.columns, section.aspectRatio)
  //
  //            itemBinding.itemsList.adapter = imagesAdapter
  
  //            val imagesAdapter = AdvanceImagesAdapter(section,context)
              itemBinding.sectionBtnViewAll.visibility = View.INVISIBLE
  
              itemBinding.section = section
              itemBinding.executePendingBindings()
  
  
              imagesAdapter.submitList((currentList[position] as AdvanceImageSection).items)
  //
  //
  //
          }
  
      }
  
      inner class CategorySectionViewHolder(private val itemBinding: HomeItemSectionBinding) :
          RecyclerView.ViewHolder(itemBinding.root) {
  
          private val categoryAdapter = HomeCategorySectionAdapter(context)
  
          fun initRecView() {
              itemBinding.itemsList.let {
  
                  val linearLayoutManager = LinearLayoutManager(
                      context,
                      LinearLayoutManager.HORIZONTAL,
                      false
                  )
  
  
                  it.layoutManager = linearLayoutManager
  
  //                it.setHasFixedSize(true)
                  it.adapter = categoryAdapter
              }
          }
  
          fun bind(position: Int) {
  
  //            (currentList[position] as CategorySection)
  
  
  
              val section = getItem(position)
              itemBinding.section = section
              itemBinding.executePendingBindings()
  
              if (categoryAdapter.itemCount &lt;= 0) {
  
                  itemBinding.pb.show()
  
                  GlobalScope.launch(Dispatchers.Main) {
                      val items = async(Dispatchers.IO) {
                          homeRepository.getSolarSearch(
                              getSolarSearchRequest(section)
                          )
                      }
  
  
                      when (items.await()) {
                          is Resource.Success -&gt; {
  
                              itemBinding.pb.hide()
                              categoryAdapter.submitList((items.await() as Resource.Success&lt;SolarSearchResponse&gt;).value.items)
                          }
                          is Resource.Failure -&gt; {
                              itemBinding.pb.hide()
                          }
                          is Resource.Loading -&gt; {
                          }
                      }
                  }
  
              }
  
  //            itemBinding.sectionBtnViewAll.setOnClickListener {
  //                homeSectionListener.onCatSectionViewAllClicked(section.categoryID.toString(),section)
  //            }
  
  
          }
  
          private fun getSolarSearchRequest(section: Section): SolarSearchRequest {
  
  
              val result = section.categoryID!! % 100
              if (result == 0) {
  
                  return SolarSearchRequest(
                      0,
                      null,
                      null,
                      25,
                      &quot;popularity&quot;,
                      arrayListOf(section.categoryID),
                      emptyList&lt;Int&gt;(),
                      selectedCondition,
                      selectedBrand,
                      &quot;1&quot;,
                      &quot;15000&quot;
                  )
  
  
                  //                    putIntegerArrayListExtra(CATEGORY_ID, arrayListOf(id))
              } else {
                  //                putIntegerArrayListExtra(SUB_CAT_ID, arrayListOf(id))
  
                  return SolarSearchRequest(
                      OFFSET,
                      null,
                      null,
                      PAGE_SIZE_LIMIT,
                      &quot;popularity&quot;,
                      emptyList&lt;Int&gt;(),
                      arrayListOf(section.categoryID),
                      selectedCondition,
                      selectedBrand,
                      &quot;1&quot;,
                      &quot;15000&quot;
                  )
  
              }
          }
      }
  
      inner class HomeBannerViewHolder(private val itemBinding: HomeBannerItemBinding) :
          RecyclerView.ViewHolder(itemBinding.root) {
  
  
  //        private val handler: Handler? = null
  //        private val delay = 5000 //milliseconds
  //        private var page = 0
  
  
          fun bind() {
  
  //            if (carousalListBinded) {
  //                return
  //            }
  
              itemBinding.carousel.start()
  
              carousalList?.let {
                  itemBinding.carousel.addData(it)
              }
  
              if (COVIDMsg.isNullOrEmpty()) {
                  itemBinding.covidMessage.visibility = View.GONE
              } else {
                  itemBinding.covidMessage.visibility = View.VISIBLE
              }
  
              itemBinding.covidMessage.text = COVIDMsg
  
              if (COVIDMsgColor != null) {
                  (itemBinding.covidMessage.background as GradientDrawable).setColor(
                      Color.parseColor(
                          COVIDMsgColor
                      )
                  )
              } else {
                  (itemBinding.covidMessage.background as GradientDrawable).setColor(
                      context.getColor(
                          R.color.colorAccent
                      )
                  )
              }
  
              carousel = itemBinding.carousel
              tvCovidMessage = itemBinding.covidMessage
  
              if (carousalList != null) {
                  carousalListBinded = true
              }
  
            
  
          }
  
          fun openNewTabWindow(urls: String, context: Context) {
              val uris = Uri.parse(urls)
              val intents = Intent(Intent.ACTION_VIEW, uris)
              val b = Bundle()
              b.putBoolean(&quot;new_window&quot;, true)
              intents.putExtras(b)
              context.startActivity(intents)
          }
  
      }
  
      inner class HomeBottomLayViewHolder(private val itemBinding: HomeScreenBottomLayoutBinding) :
          RecyclerView.ViewHolder(
              itemBinding.root
          ) {
      }
  
  
      fun getNumberOfColumns(items: List&lt;Image&gt;): Int {
  
          var numberItemsInColumn: Int = 3
  
          if ((items.size) % 3 == 0) {
              numberItemsInColumn = 3
          } else if ((items.size) % 2 == 0) {
              numberItemsInColumn = 2
          } else if (items.size == 1) {
              numberItemsInColumn = 1
          } else {
              numberItemsInColumn = 3
          }
          return numberItemsInColumn
      }
  
      @RequiresApi(Build.VERSION_CODES.M)
      fun setBanners(
          carousalList: List&lt;CarouselItem&gt;?,
          bannersList: List&lt;Banner&gt;?,
          COVIDMsg: String?,
          COVIDMsgColor: String?
      ) {
  
          this.carousalList = carousalList
          this.banners = bannersList
  
          this.COVIDMsg = COVIDMsg
          this.COVIDMsgColor = COVIDMsgColor
  
          carousalList?.let { carousel?.addData(it) }
  
          if (COVIDMsg.isNullOrEmpty()) {
              tvCovidMessage?.visibility = View.GONE
          } else {
              tvCovidMessage?.visibility = View.VISIBLE
          }
  
          tvCovidMessage?.text = COVIDMsg
  
          if (COVIDMsgColor != null &amp;&amp; tvCovidMessage != null) {
  
              (tvCovidMessage?.background as GradientDrawable).setColor(Color.parseColor(COVIDMsgColor))
          } else {
              if (tvCovidMessage != null) {
                  (tvCovidMessage?.background as GradientDrawable).setColor(context.getColor(R.color.colorAccent))
              }
          }
  
      }
  
      fun getWidth(context: Context): Int {
          var width: Int = 0
          if (Build.VERSION.SDK_INT &gt;= Build.VERSION_CODES.R) {
              val displayMetrics = DisplayMetrics()
              val display: Display? = context.display
              display!!.getRealMetrics(displayMetrics)
              return displayMetrics.widthPixels
          } else {
              val displayMetrics = DisplayMetrics()
              (context as Activity).windowManager.defaultDisplay.getMetrics(displayMetrics)
              width = displayMetrics.widthPixels
              return width
          }
      }
  
      fun getCellHeight(width: Int): Int {
  
          var height = width
  
          val ratio = 0.37
          val height1 = height * ratio
          height = height1.roundToInt()
  
          return height
      }
  
      fun setCategories(categoriesList: List&lt;Category&gt;?) {
          categoryAdapter.submitList(categoriesList)
      }
  
  }
  </code></pre>