0

I was searching for best practices to implement the home screen especially it has different sections, I found that the most common way is to create a recycler view with different view types.

it's working amazing and everything is okay except when the user starts to scroll and the trigger for the next sections start to draw it's blocking the UI thread for while to inflate the layout for the next sections, so, I'd like to ask for any suggestions to improve that situation?

am I missing something?

class HomeAdapter(
    val categoriesAdapter: HomeCategoriesAdapter,
    val offersAdapter: HomeOffersAdapter,
    val brandsAdapter: HomeBrandsAdapter,
    val preferencesUtil: PreferencesUtil,
    val bestSellAdapter: ProductsAdapter,
    val userManager: UserManager
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {

    private var userName = userManager.getUserFirstName()
    private var homeModel: HomeModel? = null

    private val userNameObserver = Observer<UserModel?> {
        userName = userManager.getUserFirstName()
        notifyItemChanged(0)
    }

    override fun onAttachedToRecyclerView(recyclerView: RecyclerView) {
        super.onAttachedToRecyclerView(recyclerView)
        userManager.userLiveData.observeForever(userNameObserver)
    }

    override fun onDetachedFromRecyclerView(recyclerView: RecyclerView) {
        userManager.userLiveData.removeObserver(userNameObserver)
        super.onDetachedFromRecyclerView(recyclerView)
    }

    override fun getItemViewType(position: Int): Int {
        return position + 1
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
        return when (viewType) {
            1 -> SectionOneVH(
                DataBindingUtil.inflate(
                    LayoutInflater.from(parent.context),
                    R.layout.SectionOneVH,
                    parent,
                    false
                )
            )

            2 -> SectionTwoVH(
                DataBindingUtil.inflate(
                    LayoutInflater.from(parent.context),
                    R.layout.SectionTwoVH,
                    parent,
                    false
                )
            )

            3 -> SectionThreeVH(
                DataBindingUtil.inflate(
                    LayoutInflater.from(parent.context),
                    R.layout.SectionThreeVH,
                    parent,
                    false
                )
            )

            4 -> SectionFourVH(
                DataBindingUtil.inflate(
                    LayoutInflater.from(parent.context),
                    R.layout.SectionFourVH,
                    parent,
                    false
                )
            )

            5 -> SectionFiveVH(
                DataBindingUtil.inflate(
                    LayoutInflater.from(parent.context),
                    R.layout.SectionFiveVH,
                    parent,
                    false
                )
            )

            6 -> SectionSixVH(
                DataBindingUtil.inflate(
                    LayoutInflater.from(parent.context),
                    R.layout.SectionSixVH,
                    parent,
                    false
                )
            )

            7 -> SectionSevenVH(
                DataBindingUtil.inflate(
                    LayoutInflater.from(parent.context),
                    R.layout.SectionSevenVH,
                    parent,
                    false
                )
            )
            else -> SectionOneVH(
                DataBindingUtil.inflate(
                    LayoutInflater.from(parent.context),
                    R.layout.SectionOneVH,
                    parent,
                    false
                )
            )
        }
    }

    override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
        when (holder) {
            // each bind has text & recycler declaration & click lisners in the init block
            is SectionOneVH -> holder.bind()
            is SectionTwoVH -> holder.bind()
            is SectionThreeVH -> holder.bind()

            is SectionFourVH -> holder.bind()

            is SectionFiveVH -> holder.bind()
            is SectionSixVH -> holder.bind()

        }
    }

    override fun getItemCount() = 7

    fun pushData(homeModel: HomeModel) {
        this.homeModel = homeModel
        notifyDataSetChanged()
    }

    inner class SectionOneVH(private val binding: SectionOneBinding) :
        private val context = binding.root.context

        fun bind() {
            // logic for binding the SectionOneVH
        }

    }

    inner class SectionTwoVH(private val binding: SectionTwoBinding) :
            
        fun bind() {
            // logic for binding the SectionTwoVH
        }
    }

    inner class SectionThreeVH(private val binding: SectionThreeBinding) :

        fun bind() {
            // logic for binding the SectionThreeVH
        }

    }

    inner class SectionFourVH(private val binding: SectionFourBinding) :

        fun bind() {
            // logic for binding the SectionFourVH
        }
    }

    inner class SectionFiveVH(private val binding: SectionFiveBinding) :
            
        fun bind() {
            // logic for binding the SectionFiveVH
        }
    }

    inner class SectionSixVH(private val binding: SectionSixBinding) :
            
        fun bind() {
            // logic for binding the SectionFourVH
        }
    }

    inner class SectionSevenVH(private val binding: SectionSevenBinding) :
    
        fun bind() {
            // logic for binding the SectionFourVH
        }
    }
}
Moustafa EL-Saghier
  • 1,721
  • 1
  • 13
  • 43
  • Hard to answer without more information as lots of things could be causing the RecyclerView to be slow (by the way, it was specifically designed to be Fast!). The most common guess would be is that the adapter's `onBindViewHolder()` is doing something that takes time. It could be inflating a View (which should only happen in `onCreateViewHolder()` or most likely: you may be accessing data which takes time. You could add a callback to the data so that it loads later, when the data is ready. It's perfectly ok to draw a RecyclerView item and then load its data when the data comes in. – SMBiggs Jan 23 '22 at 00:11
  • @SMBiggs i'm doing in `onBindViewHolder` the view binding depend on the holder value to be suitable for different layouts, and in the `onCreateViewHolder` i'm doing same as you said for the inflating. regarding to the data ready it's already there in the viewmodel object for home-model so i'm taking the brands & best selling data from that model to display it but there is like stuck in the rendering i can't find the reason, any suggestions? – Moustafa EL-Saghier Jan 23 '22 at 00:18
  • without any code it's impossible to help you – Ivan Wooll Jan 23 '22 at 10:31
  • @IvanWooll I've added the adapter code can you take a look? – Moustafa EL-Saghier Jan 23 '22 at 11:21
  • Thanks for the code--it helps. What's happening in the `bind()` functions? Could the logic there be taking time? It's something that will be called often when scrolled. – SMBiggs Jan 24 '22 at 15:09
  • @SMBiggs it differs from view type to other for example some showing slider, another recycler for brands, other for best selling, and all of them are just display data the ones which are heavy are recycler for brands & best selling products ( display 10 only ) ... just bind data to recycler after declare layout manger and adapter for each – Moustafa EL-Saghier Jan 24 '22 at 20:50
  • @MoustafaEL-Saghier Ah, if you are inflating different layouts in the `bind()` function, that could do it. Inflating takes a lot of time. Since you have different types of layouts, you may need to implement `getItemViewType()` or write a custom ViewHolder class--one that handles multiple layout types. Let me know if this is the case for your app, and I'll show you a way to do it (or read this answer here: https://stackoverflow.com/a/26245463/624814). – SMBiggs Jan 25 '22 at 22:05
  • please re-read the code again i've `onCreateViewHolder` for inflating and there's already a `getItemViewType` my case is I've 7 view type one is slider and reset are recycler view each row for recycler has title + recycler item like section of brands, I show title as brands and recycler of brands list – Moustafa EL-Saghier Jan 26 '22 at 19:21

0 Answers0