簡體   English   中英

嵌套 Recyclerview 使滾動滯后

[英]Nested Recyclerview makes scroll laggy

我正在使用具有多視圖類型的 recyclerview 並使用嵌套的 recyclerviews:

在此處輸入圖像描述

但它的滾動非常緩慢。 我還處理了 onViewRecycled function 中的子 recyclerviews 滾動 position:

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<RecyclerView>(R.id.itemsList)
                .layoutManager?.onSaveInstanceState()
    }
}

而在 onBindViewHolder

val state = scrollStates[key]
        if (state != null) {
            itemBinding.itemsList.layoutManager?.onRestoreInstanceState(state)
        } else {
            itemBinding.itemsList.layoutManager?.scrollToPosition(0)
        }

我也試過:

binding.rvHome.recycledViewPool.setMaxRecycledViews(0, 0);

我正在將 ListAdapter 與 DiffUtils 一起使用。 我還嘗試將適配器設置為 onCreateViewHolder 中的子回收視圖,並從 onBindViewHolder 提交列表,還嘗試從 onBindViewHolder 設置適配器。 但在所有情況下,主要回收者視圖回收視圖和滯后。 我不想禁用recyclerview的回收。

誰能建議我在這里做錯了什么。

代碼:

class MainAdapter(
    private val context: Context,
    private val currentLocale: String,
    private val currentCountry: String,
    private val homeRepository: HomeRepository
) :
    ListAdapter<Section, RecyclerView.ViewHolder>(Companion) {

    var selectedCondition: List<Int?>? = emptyList()
    var selectedBrand: MutableList<Int?>? = arrayListOf()

    private var carousalListBinded: Boolean = false

    private var carousalList: List<CarouselItem>? = null
    private var banners: List<Banner>? = 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<Section>() {
        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 -> {

                val categoryViewHolder = CategoryViewHolder(
                    DataBindingUtil.inflate(
                        LayoutInflater.from(parent.context),
                        R.layout.home_categories_item,
                        parent,
                        false
                    )
                )

                categoryViewHolder.initRecView()

                return categoryViewHolder

            }
            VIEW_TYPE_ITEM_SECTION -> {

                val homeSectionsViewHolder = HomeSectionsViewHolder(
                    DataBindingUtil.inflate(
                        LayoutInflater.from(parent.context),
                        R.layout.home_item_section,
                        parent,
                        false
                    )
                )

                homeSectionsViewHolder.initRecView()

                return homeSectionsViewHolder
            }
            VIEW_TYPE_BRAND -> {

                val brandsViewHolder = BrandsViewHolder(
                    DataBindingUtil.inflate(
                        LayoutInflater.from(parent.context),
                        R.layout.home_brands_item,
                        parent,
                        false
                    )
                )

                brandsViewHolder.initRecView()

                return brandsViewHolder
            }
            VIEW_TYPE_IMAGE -> {

                val imagesViewHolder = ImagesViewHolder(
                    DataBindingUtil.inflate(
                        LayoutInflater.from(parent.context),
                        R.layout.home_brands_item,
                        parent,
                        false
                    )
                )

                imagesViewHolder.initRecView()

                return imagesViewHolder

            }
            VIEW_TYPE_ADVANCE_IMAGE -> {

                val advanceImagesViewHolder = AdvanceImagesViewHolder(
                    DataBindingUtil.inflate(
                        LayoutInflater.from(parent.context),
                        R.layout.home_brands_item,
                        parent,
                        false
                    )
                )

                advanceImagesViewHolder.initRecView()

                return advanceImagesViewHolder
            }
            VIEW_TYPE_ADVANCE_CATEGORY -> {

                val categorySectionViewHolder = CategorySectionViewHolder(
                    DataBindingUtil.inflate(
                        LayoutInflater.from(parent.context),
                        R.layout.home_item_section,
                        parent,
                        false
                    )
                )

                categorySectionViewHolder.initRecView()

                return categorySectionViewHolder

            }
            VIEW_TYPE_BANNER -> {

                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 -> {
                return HomeBottomLayViewHolder(
                    DataBindingUtil.inflate(
                        LayoutInflater.from(parent.context),
                        R.layout.home_screen_bottom_layout,
                        parent,
                        false
                    )
                )
            }
            else -> {

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

                (holder as CategoryViewHolder).bind(position)
            }
            VIEW_TYPE_ITEM_SECTION -> {

                (holder as HomeSectionsViewHolder).bind(position)

            }
            VIEW_TYPE_BRAND -> {
                (holder as BrandsViewHolder).bind(position)
            }
//
            VIEW_TYPE_IMAGE -> {
                (holder as ImagesViewHolder).bind(position)
            }
//
            VIEW_TYPE_ADVANCE_IMAGE -> {
                (holder as AdvanceImagesViewHolder).bind(position)
            }

            VIEW_TYPE_ADVANCE_CATEGORY -> {
                (holder as CategorySectionViewHolder).bind(position)
            }

            VIEW_TYPE_BANNER -> {
//                (holder as HomeBannerViewHolder).setIsRecyclable(false)
                (holder as HomeBannerViewHolder).bind()
            }

            VIEW_TYPE_HOME_BOTTOM_SECTION -> {
                (holder as HomeBottomLayViewHolder)
            }
        }

//        holder.itemView.setFadeAnimation()

    }

    override fun getItemViewType(position: Int): Int {

        return when (currentList[position].sectionType) {
            SectionType.items -> {
                VIEW_TYPE_ITEM_SECTION
            }
            SectionType.brands -> {
                VIEW_TYPE_BRAND
            }
            SectionType.images -> {
                VIEW_TYPE_IMAGE
            }
            SectionType.advanceimages -> {
                VIEW_TYPE_ADVANCE_IMAGE
            }
            SectionType.category -> {
                VIEW_TYPE_ADVANCE_CATEGORY
            }
            SectionType.banners -> {
                VIEW_TYPE_BANNER
            }
            SectionType.homeCategories -> {
                VIEW_TYPE_CATEGORY
            }
            SectionType.homeBottomView -> {
                VIEW_TYPE_HOME_BOTTOM_SECTION
            }
            else -> {
                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 <= 0) {

                itemBinding.pb.show()

                GlobalScope.launch(Dispatchers.Main) {
                    val items = async(Dispatchers.IO) {
                        homeRepository.getSolarSearch(
                            getSolarSearchRequest(section)
                        )
                    }


                    when (items.await()) {
                        is Resource.Success -> {

                            itemBinding.pb.hide()
                            categoryAdapter.submitList((items.await() as Resource.Success<SolarSearchResponse>).value.items)
                        }
                        is Resource.Failure -> {
                            itemBinding.pb.hide()
                        }
                        is Resource.Loading -> {
                        }
                    }
                }

            }

//            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,
                    "popularity",
                    arrayListOf(section.categoryID),
                    emptyList<Int>(),
                    selectedCondition,
                    selectedBrand,
                    "1",
                    "15000"
                )


                //                    putIntegerArrayListExtra(CATEGORY_ID, arrayListOf(id))
            } else {
                //                putIntegerArrayListExtra(SUB_CAT_ID, arrayListOf(id))

                return SolarSearchRequest(
                    OFFSET,
                    null,
                    null,
                    PAGE_SIZE_LIMIT,
                    "popularity",
                    emptyList<Int>(),
                    arrayListOf(section.categoryID),
                    selectedCondition,
                    selectedBrand,
                    "1",
                    "15000"
                )

            }
        }
    }

    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("new_window", true)
            intents.putExtras(b)
            context.startActivity(intents)
        }

    }

    inner class HomeBottomLayViewHolder(private val itemBinding: HomeScreenBottomLayoutBinding) :
        RecyclerView.ViewHolder(
            itemBinding.root
        ) {
    }


    fun getNumberOfColumns(items: List<Image>): 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<CarouselItem>?,
        bannersList: List<Banner>?,
        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 && 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 >= 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<Category>?) {
        categoryAdapter.submitList(categoriesList)
    }

}

您的代碼中一切都很好,主要問題在於您用於獲取數據的線程。 這是官方文檔所說的:

熟練使用 Android 上的線程可以幫助您提高應用程序的性能。

如果你在主UI 線程上做的太多,那么滯后是可以理解的,因為 UI 線程應該只負責繪制,而不是獲取和解析業務問題。 要解決您的問題,請使用 Kotlin 協程作為您的業務規則。 這是我在互聯網上找到的兩個最好的資源,它是免費的: Kotlin android高級 Kotlin ZC31B32364CE7EC19CA84

有用的鏈接Android 性能

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM