我正在使用具有多视图类型的 recyclerview 并使用嵌套的 recyclerviews:
但是它的滚动速度很慢。我还在 onViewRecycled 函数中处理了子 recyclerviews 滚动位置:
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 中将适配器设置为子 recyclerviews,并从 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)
}
}