Last active
July 25, 2023 06:48
-
-
Save AliAzaz/fea768c495c33f049ebec86365c2a37b to your computer and use it in GitHub Desktop.
Generic RecyclerAdapter implementtion using DiffUtils
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
private lateinit var adapter: GenericListAdapter<ImagesInfo> | |
adapter = GenericListAdapter(R.layout.product_view) { item, position -> | |
viewModel.setSelectedProduct(item) | |
findNavController().navigate(ImageListFragmentDirections.actionImageListFragmentToImageDetailFragment()) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Adapter | |
class GenericListAdapter<T> internal constructor( | |
@IdRes private val layout: Int, | |
private val clickListener: (item: T, position: Int) -> Unit | |
) : RecyclerView.Adapter<GenericViewHolder<T>>() { | |
var productItems: ArrayList<T> = ArrayList() | |
set(value) { | |
field = value | |
val diffCallback = | |
GenericViewHolder.ChildViewDiffUtils(filteredProductItems, productItems) | |
val diffResult = DiffUtil.calculateDiff(diffCallback) | |
if (filteredProductItems.size > 0) | |
filteredProductItems.clear() | |
filteredProductItems.addAll(value) | |
diffResult.dispatchUpdatesTo(this) | |
} | |
private var filteredProductItems: ArrayList<T> = ArrayList() | |
set(value) { | |
field = value | |
val diffCallback = | |
GenericViewHolder.ChildViewDiffUtils(filteredProductItems, productItems) | |
val diffResult = DiffUtil.calculateDiff(diffCallback) | |
diffResult.dispatchUpdatesTo(this) | |
} | |
fun clearProductItem() { | |
filteredProductItems.clear() | |
} | |
override fun onCreateViewHolder(viewGroup: ViewGroup, i: Int): GenericViewHolder<T> { | |
val layoutInflater = LayoutInflater.from(viewGroup.context) | |
val binding = DataBindingUtil.inflate<ViewDataBinding>(layoutInflater, i, viewGroup, false) | |
return GenericViewHolder(binding) | |
} | |
override fun onBindViewHolder(holder: GenericViewHolder<T>, i: Int) { | |
val item = filteredProductItems[i] | |
holder.bind(item) | |
holder.itemView.parentLayout.setOnClickListener { | |
clickListener(item, i) | |
} | |
} | |
override fun getItemCount(): Int = filteredProductItems.size | |
override fun getItemViewType(position: Int) = layout | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ViewHolder | |
class GenericViewHolder<T>(private val bi: ViewDataBinding) : | |
RecyclerView.ViewHolder(bi.root) { | |
fun bind(item: T) { | |
bi.apply { | |
bi.setVariable(BR.item, item) | |
bi.executePendingBindings() | |
} | |
} | |
class ChildViewDiffUtils<T>( | |
private val oldList: ArrayList<T>, | |
private val newList: ArrayList<T> | |
) : | |
DiffUtil.Callback() { | |
override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean { | |
return oldList[oldItemPosition].toString() == newList[newItemPosition].toString() | |
} | |
override fun getOldListSize(): Int { | |
return oldList.size | |
} | |
override fun getNewListSize(): Int { | |
return newList.size | |
} | |
override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean { | |
return oldList[oldItemPosition] == newList[newItemPosition] | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hi @AliAzaz is the code right? In the overridden method
areItemsTheSame
you are using.toString
which will fail for example for afor the same registered car
Car(registrationId = "abc", currentColor = "red")
andCar(registrationId = "abc", currentColor = "yellow")
your code will treat these as different item while onlyareContentsTheSame
should return false as these two elements have different data. But you code will WRONGLY return theareItemsTheSame
as false as well.Or is this code specific to your use case only? In that case it should not be present inside
GenericViewHolder.kt