nested recyclerview using paging adapter (paging 3) show wrong image after scrolling

1.2k views Asked by At

How to solve the child adapter image that changes and show wrong images after scrolling?

this is my code

Parent Data Class

data class Review(
   val author: String,
   val date: String,
   val rating: Float,
   val comment: String,
   val images: List<Image>)

Child Data Class

For author and comment, I only take it from the parent data class

data class Image(
   var author: String? = null,
   var comment: String? = null,
   val large: String,
   val thumbnail: String)

ParentAdapter

class ReviewAdapter(private val callback: ProductReviewImageAdapterCallback) :
PagingDataAdapter<Review, ReviewAdapter.ListViewHolder>(DIFF_CALLBACK) {

private val viewPool = RecyclerView.RecycledViewPool()

private val imageAdapter: ProductReviewImageAdapter by lazy {
    ProductReviewImageAdapter(callback)
}

companion object {
    private val DIFF_CALLBACK = object : DiffUtil.ItemCallback<Review>() {
        override fun areItemsTheSame(oldItem: Review, newItem: Review): Boolean {
            return oldItem.author == newItem.author
        }

        override fun areContentsTheSame(oldItem: Review, newItem: Review): Boolean {
            return oldItem.comment == newItem.comment
        }
    }
}


inner class ListViewHolder(itemBinding: ItemProductReviewBinding) :
    RecyclerView.ViewHolder(itemBinding.root) {
    val binding = ItemProductReviewBinding.bind(itemBinding.root)
    fun bind(data: Review, position: Int) {
      with(binding) {
            if (data.images.isEmpty()) {
                rvImageReview.gone()
            } else {
                setupImagesRecyclerView(rvImageReview)
                rvImageReview.visible()
                imageAdapter.differ.submitList(data.images)
            }

            tvNameReviewer.text = data.author
            tvReviewDesc.text = data.comment
            tvDateReview.text = data.date
            ratingBarReview.rating = data.rating

        }
    }
}


override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ListViewHolder =
    ListViewHolder(
        ItemProductReviewBinding.inflate(LayoutInflater.from(parent.context), parent, false)
    )

override fun onBindViewHolder(holder: ListViewHolder, position: Int) {
    val review = getItem(position)

    if (review != null) {
        holder.bind(review, position)
    }
}

private fun setupImagesRecyclerView(recyclerView: RecyclerView) {
    recyclerView.apply {
        layoutManager = LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false)
        adapter = imageAdapter
        setRecycledViewPool(viewPool)
        setItemViewCacheSize(20)
    }
}

}

ChildAdapter

class ProductReviewImageAdapter(private val callback: ProductReviewImageAdapterCallback) : RecyclerView.Adapter<ProductReviewImageAdapter.ListViewHolder>() {
private val diffCallback = object : DiffUtil.ItemCallback<Image>() {
    override fun areItemsTheSame(
        oldItem: Image,
        newItem: Image
    ): Boolean {
        return oldItem.author == newItem.author
    }

    override fun areContentsTheSame(
        oldItem: Image,
        newItem: Image
    ): Boolean {
        return oldItem.comment == newItem.comment
    }

}

val differ = AsyncListDiffer(this, diffCallback)

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ListViewHolder =
    ListViewHolder(
        ItemImageBinding.inflate(LayoutInflater.from(parent.context), parent, false)
    )

override fun getItemCount(): Int = differ.currentList.size

override fun onBindViewHolder(holder: ListViewHolder, position: Int) {
    holder.bind(differ.currentList[position], position)
}

inner class ListViewHolder(itemBinding: ItemImageBinding) :
    RecyclerView.ViewHolder(itemBinding.root) {
    private val itemBinding = ItemImageBinding.bind(itemBinding.root)
    fun bind(data: Image, position: Int) {
        with(itemBinding) {

            image.loadImageRoundedCorner(data.thumbnail)

            image.setOnClickListener {
                callback.onProductReviewImageClicked(position, differ.currentList)
            }

        }

    }
}

}

Before scrolling

on first load, the first position data displays the appropriate image

before scrolling

After a bit scrolling

the image in the first position data changes to the image in the next data

after a bit scrolling

Scroll to last data/page

the last image shows an unsuitable image

scroll to last data/page

*Note

  • there is only 5 data, and only first and last data contains image
  • The image in the first position data should be a person image and the last position image should be a pink image
  • I use Coil as the image loader and have used the ImageView.clear() method before loading the image

Thanks in advance, sorry if my english is bad. I'm not a native speaker

1

There are 1 answers

0
Ilham Budi Prasetyo On BEST ANSWER

Update

Fixed : it turned out that it was only wrong at the time of adapter initialization, the adapter should be initialized in onBindViewHolder, not in the parent adapter so that not all items have the same adapter which causes all data to change