androidkotlinandroid-livedataandroid-diffutils

How can DiffUtil know about list changes when only the companion object has changed?


enter image description here

As shown in the image, I would like the unit of the Detail item to be changed at once according to the toggle button.

Detail list items were set as companion objects because it was determined that it was not necessary to have a unit property individually.

However, it seems that DiffUtil determines that there is no change between the new list and the old list, perhaps because the unit property is set as a companion object.

So there is no update of the view either.

How can I make DiffUtil responsive while changing the companion object?


Detail

@Entity
data class Detail(
    @PrimaryKey(autoGenerate = true)
    var id: Int,
    val set: Int,
    var weight: String = "",
    var reps: String = "") {

    companion object {
        var title: String = ""
        var unit: String = "kg"
        val memo = ""
    }
}

ViewModel

class DetailViewModel(application: Application) : ViewModel() {
    private val repository: DetailRepository
    private val _items: MutableLiveData<List<Detail>> = MutableLiveData()
    val items = _items
    private val list: List<Detail>
        get() = _items.value ?: emptyList()

    init {
        val detailDao = DetailDatabase.getDatabase(application)!!.detailDao()
        repository = DetailRepository(detailDao)
    }

    fun changeUnit(unit: String) {
        Detail.unit = unit
        if(list == null)
            return

        _items.postValue(list) // To notify the observer.
    }

    fun addDetail() {

        viewModelScope.launch(Dispatchers.IO){
            val item = Detail(0, set = list.size+1)
            repository.add(item)

            // If use plus(), a new List is returned.
            // Therefore, the change is notified to the Observer by postValue of the new list added.
            _items.postValue(list.plus(item))

        }
    }
    fun deleteDetail() {
        // Delete the last set and return a new list to postValue to notify the Observer of the change.
        _items.postValue(list.dropLast(1))
    }
}

DiffUtil

class DetailDiffCallback : DiffUtil.ItemCallback<Detail>() {
    override fun areItemsTheSame(
        oldItem: Detail,
        newItem: Detail
    ): Boolean  {
       return (oldItem.id == newItem.id)
    }

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

Fragment

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    vm.items.observe(viewLifecycleOwner) { newList ->
        adapter.submitList(newList)
    }
}

Solution

  • Detail list items were set as companion objects because it was determined that it was not necessary to have a unit property individually.

    This is the root of the problem. If you want DiffUtil to be able to "see" these changes, you will have to move this information out of the companion object.

    DiffUtil works by taking in two instances of your class and doing work (the areItemsTheSame() and areContentsTheSame() methods) to see if anything has changed. Since this information is part of the companion object, it will always be identical for all instances, which means there's no way for DiffUtil to detect a change, even if one has happened.