I am using LiveData to fetch 30 items from the database like this:
@Query("SELECT * FROM table ORDER BY id DESC LIMIT 30")
fun getLast30(): LiveData<List<Person>>
Every recycler view item has a like button and I have an interface in the adapter:
interface OnItemClickedAdapter {
fun onFavButtonClicked(position: Int)
}
end when the like button clicked I am updating a single item in the database. As I am using LiveData it is fetching updated 30 items. I am setting that data using observe metod:
viewModel.last30.observe(viewLifecycleOwner, {
adapter.submitList(it)
}
Problem:
Edited: submitList(list: List) method:
fun submitList(persons: List<Person>) {
val diffResult: DiffUtil.DiffResult = DiffUtil.calculateDiff(
ApodGalleryAdapterDiffCallback(
this.persons,
persons
)
)
this.persons = person
diffResult.dispatchUpdatesTo(this)
}
DiffUtill class:
class PersonAdapterDiffCallback(var oldList: List<Person>, var newList: List<Person>) :
DiffUtil.Callback() {
override fun getOldListSize(): Int {
return oldList.size
}
override fun getNewListSize(): Int {
return newList.size
}
override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
return oldList[oldItemPosition].url == newList[newItemPosition].url
}
override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
return oldList[oldItemPosition] == newList[newItemPosition]
}
}
Adapter class:
class ApodGalleryAdapter() :
RecyclerView.Adapter<ApodGalleryAdapter.ApodGalleryViewHolder>() {
var onItemClickedGalleryAdapter: OnItemClickedGalleryAdapter? = null
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ApodGalleryViewHolder {
return ApodGalleryViewHolder(
LayoutInflater.from(parent.context).inflate(R.layout.item_apod_gallery, parent, false),
onItemClickedGalleryAdapter
)
}
private var apods: List<Apod> = ArrayList()
override fun getItemCount(): Int {
return apods.size
}
override fun onBindViewHolder(holder: ApodGalleryViewHolder, position: Int) {
holder.bindData(apods[position], position)
}
fun submitList(apods: List<Apod>) {
val diffResult: DiffUtil.DiffResult = DiffUtil.calculateDiff(
ApodGalleryAdapterDiffCallback(
this.apods,
apods
)
)
this.apods = apods
diffResult.dispatchUpdatesTo(this)
}
class ApodGalleryViewHolder(
itemView: View,
var onItemClickedGalleryAdapter: OnItemClickedGalleryAdapter?
) :
RecyclerView.ViewHolder(itemView) {
private val apodImage: ImageView = itemView.image_item_apod
private val apodTitle: TextView = itemView.title_item_apod
private val apodDescription: TextView = itemView.description_item_apod
private val apodCopyright: TextView = itemView.copyright_item_apod
fun bindData(apod: Apod, position: Int) {
when {
apod.url.endsWith(".jpg") -> {
Glide.with(apodImage.context)
.load(apod.url)
.placeholder(R.drawable.transparent)
.into(apodImage)
}
apod.url.contains("youtube") -> {
Glide.with(apodImage.context)
.load(getThumbnailUrl(apod.url))
.placeholder(R.drawable.transparent)
.into(apodImage)
}
else -> {
apodImage.setImageResource(R.drawable.transparent)
}
}
apodTitle.text = apod.title
apodDescription.text = apod.explanation
apodCopyright.text = apod.copyright
if (apod.isLiked) {
itemView.fav_button_item_apod_gallery.setImageResource(R.drawable.ic_round_favorite_24)
} else {
itemView.fav_button_item_apod_gallery.setImageResource(R.drawable.ic_round_favorite_border_24)
}
itemView.setOnClickListener {
onItemClickedGalleryAdapter?.onClick(apod.date)
}
itemView.fav_button_item_apod_gallery.setOnClickListener {
onItemClickedGalleryAdapter?.onFavButtonClicked(position)
}
}
}
}
interface OnItemClickedGalleryAdapter {
fun onClick(date: String)
fun onFavButtonClicked(position: Int)
}
class ApodGalleryAdapterDiffCallback(var oldList: List<Apod>, var newList: List<Apod>) :
DiffUtil.Callback() {
override fun getOldListSize(): Int {
return oldList.size
}
override fun getNewListSize(): Int {
return newList.size
}
override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
return oldList[oldItemPosition].url == newList[newItemPosition].url
}
override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
return oldList[oldItemPosition] == newList[newItemPosition]
}
}
I have overwritten the equals()
method of my Data class:
override fun equals(other: Any?): Boolean {
if (javaClass != other?.javaClass)
return false
other as Apod
if (id != other.id)
return false
if (copyright != other.copyright)
return false
if (date != other.date)
return false
if (explanation != other.explanation)
return false
if (hdUrl != other.hdUrl)
return false
if (media_type != other.media_type)
return false
if (service_version != other.service_version)
return false
if (url != other.url)
return false
if (isLiked != other.isLiked)
return false
return true
}
I was such a fool searching the solution througth liveData, DiffUtill and adapter.notifyItemChanged(position)
The real problem was in my observer block:
viewModel.apod30Days.observe(viewLifecycleOwner, {
adapter.submitList(it)
adapter.onItemClickedGalleryAdapter = object : OnItemClickedGalleryAdapter {
override fun onClick(date: String) {
val intent =
Intent(requireActivity().applicationContext, DetailsActivity::class.java)
intent.putExtra(DetailsActivity.APOD_DATE_KEY, date)
startActivity(intent)
}
override fun onFavButtonClicked(position: Int) {
val apod = it[position]
apod.isLiked = !apod.isLiked
viewModel.updateApod(apod)
adapter.notifyItemChanged(position)
}
}
if (it.size < 30)
viewModel.setLast30Apods()
binding.apodViewPager.adapter = adapter
})
In this block's last line, I am setting the adapter again and again when the liveData changes. DiffUtill was working perfectly.