AndroidDev123
AndroidDev123

Reputation: 370

Diff util not updating UI - Multitype recyclerview - Model contains lists

I have a recyclerview which displays multiple viewholders containing horizontal rows, grids, vertical lists etc so my Model that I pass to the recyclerview has a few different lists contained in it.

Some of the data in the List is genereated by dagger at compile time and other lists within that model are updated when the network requests from the api completes.

The problem is when I pass the updated List the UI never updates. I have to move into another screen then come back again to see the UI updated or just manually pass false in the diff util areContentsTheSame

Model

data class Model(
var id: String,
val viewType: String,
val title: Int?,
val textColour: Int,
val order: Int,
var header: HeaderModel?,
var videoList: List<VideoModel>? = emptyList(),
var quotesList: List<QuotesModel>? = emptyList(),
var tileList: List<TileModel>? = emptyList(),
var gratitudeList: List<String>? = emptyList(),
) {
override fun equals(other: Any?): Boolean {
    if (this === other) return true
    if (javaClass != other?.javaClass) return false

    other as Model

    if (id != other.id) return false
    if (viewType != other.viewType) return false
    if (title != other.title) return false
    if (textColour != other.textColour) return false
    if (order != other.order) return false
    if (header != other.header) return false
    if (videoList != other.videoList) return false
    if (quotesList != other.quotesList) return false
    if (tileList != other.tileList) return false
    if (gratitudeList != other.gratitudeList) return false

    return true
}

Adapter Diff

 val DIFF_CALLBACK = object : DiffUtil.ItemCallback<Model>() {
    override fun areItemsTheSame(
        oldItem: Model,
        newItem: Model
    ): Boolean {
        val value = oldItem.id == newItem.id
        return value
    }

    override fun areContentsTheSame(
        oldItem: Model,
        newItem: Model
    ): Boolean {
         return oldItem == newItem
    }
}

private val differ = AsyncListDiffer(this, DIFF_CALLBACK)

fun submitList(list: List<Model>?) {
    differ.submitList(list)
    //  notifyDataSetChanged()
}

Fragment

homeViewModel.viewState.observe(viewLifecycleOwner, { viewState ->
        if (viewState != null) {
            viewState.modelList?.let { list ->
                homeAdapter?.submitList(list)
            }
        }
    })

Update to the videoList

 fun updateListVideos(list:  List<VideoModel>?) {
    val update = getCurrentViewStateOrNew()
    setViewState(update.apply{ modelList?.get(1)?.videoList = list)
}

I've read so many other questions on this that suggest in the live data observer pass list.toMutableList to essentially create a new list - Tried it doesnt work. The only hack that worked was calling submitList(null) before submitting the list which causes the whole UI to "flash". Other than that Ive had to revert back to NotifyDataSetChange which obviously defeats the whole purpose of having a diff util. Any help solving this would be great.

Upvotes: 0

Views: 416

Answers (1)

Akn
Akn

Reputation: 501

Your old and new lists have the same referenced fields. That's why, diff util is not recognizing the change. You should either update your equals override and compare each field of lists or when you want to update your oldList do it like below:

val newList = oldList.map { it.copy() }
homeAdapter?.submitList(newList)

Upvotes: 0

Related Questions