4

I have made an adapter for a recyclerView and used DiffUtil to show the updation of the list in a fancier way. I used google codelabs for a reference for this. But the list is not updating from the following code. Please help

class LaptopAdapter : ListAdapter<Laptop, LaptopAdapter.ViewHolder>(Diff()) {

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        return ViewHolder.from(parent)
    }

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        val item = getItem(position)
        holder.bind(item)
    }

    class ViewHolder private constructor(itemView: View) : RecyclerView.ViewHolder(itemView) {
        var ramText: TextView = itemView.findViewById(R.id.ramText)
        var diskText: TextView = itemView.findViewById(R.id.diskText)
        var screenText: TextView = itemView.findViewById(R.id.screenText)
        var osText: TextView = itemView.findViewById(R.id.osText)

        fun bind(item: Laptop) {
            ramText.text = item.ram.toString()
            diskText.text = item.disk
            screenText.text = item.screen.toString()
            osText.text = item.os
        }

        companion object {
            fun from(parent: ViewGroup) =
                    ViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.item, parent, false))
        }
    }
}

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

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

My MainActivity file is

setContentView(R.layout.activity_main)

        val list: ArrayList<Laptop> = ArrayList()
        list.add(Laptop(11, 4, "SSD", 14, "Windows"))
        list.add(Laptop(12, 4, "HDD", 14, "Ubuntu"))
        list.add(Laptop(17, 16, "SSD", 14, "Windows"))
        list.add(Laptop(13, 8, "SSD", 14, "Windows"))

        val rv: RecyclerView = findViewById(R.id.rv)
        rv.layoutManager = LinearLayoutManager(this)
        val adapter = LaptopAdapter()
        rv.adapter = adapter
        adapter.submitList(list)

        val btn: Button = findViewById(R.id.btn)
        btn.setOnClickListener {
            list.add(Laptop(15, 12, "HDD", 12, "DOS"))
            list.sortBy {
                it.ram
            }
            adapter.submitList(list)
        }

I tried previous stackOverflow answers and none were working. Please help

Selman Tosun
  • 428
  • 5
  • 14
potatoxchip
  • 516
  • 1
  • 7
  • 20

1 Answers1

15

If you check in source code of ListAdapter how submitList work you will find this part of code:

if (newList == mList) {
   // nothing to do (Note - still had to inc generation, since may have ongoing work)
   return;
}

so until you pass the list with the same reference you will never update your list. To make it work you can simply invoke:

adapter.submitList(list.toList())
Matt Twig
  • 444
  • 3
  • 8
  • 1
    This works like a charm. But how would the reference change? – potatoxchip Jul 04 '19 at 05:53
  • When you use the same list object as before then reference is the same. Kotlin extension `toList()` create completely new list with data. The best way to avoid this type of problem is create not mutable list - when you would like add something to list you have to create new one – Matt Twig Jul 04 '19 at 05:56
  • Ok so everytime I update the list, I have to either pass a new list, or the existing list should be immutable? – potatoxchip Jul 04 '19 at 05:58
  • Yes, but better solution is create immutable list because when you use mutable list some errors can occur ex. when you edit a list that is not mutable and call notifyDataChanged on adapter probably list will be updated even if you don't call `submitList()` – Matt Twig Jul 04 '19 at 06:01