DiffUtil Not working with ListAdpater when view is updating Android Kotlin

vivek modi

Hey I have Reyclerview with DiffUtill using ListAdapter. I added element through submitList function. But when updating the list view is not redrawing the element. Until I used notifyDataSetChanged() or setting adapter again. So what the use case of DiffUtill?. What is the proper way of doing to redraw item when item is updated in list as well as in reyclerview.

MainActivity

class MainActivity : AppCompatActivity() {

    private var list = mutableListOf(1, 2, 3, 4, 5, 6, 7, 8, 9)
    private lateinit var binding: ActivityMainBinding
    var i = 0

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)
        Log.e("List", " $list")
        val intAdapter = IntAdapter()
        binding.recylerview.adapter = intAdapter
        intAdapter.submitList(list)
        binding.button.setOnClickListener {
            list.add(++i)
            intAdapter.submitList(list)
//            binding.recylerview.adapter = intAdapter
//            intAdapter.notifyDataSetChanged()
        }
    }
}

IntAdapter

class IntAdapter : ListAdapter<Int, IntViewHolder>(comparator) {

    companion object {
        private val comparator = object : DiffUtil.ItemCallback<Int>() {
            override fun areItemsTheSame(oldItem: Int, newItem: Int): Boolean {
                return oldItem == newItem
            }

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

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): IntViewHolder {
        return IntViewHolder(
            IntLayoutBinding.inflate(
                LayoutInflater.from(parent.context),
                parent,
                false
            )
        )
    }

    override fun onBindViewHolder(holder: IntViewHolder, position: Int) {
        holder.bindItem(getItem(position))
    }

}

IntViewHolder

class IntViewHolder(val binding: IntLayoutBinding) : RecyclerView.ViewHolder(binding.root) {

    fun bindItem(item: Int?) {
        binding.intNumber.text = item.toString()
    }

}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <androidx.recyclerview.widget.RecyclerView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/recylerview"
        app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="add"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

int_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <TextView
        android:id="@+id/intNumber"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>
Tenfour04

You need to ensure you pass a different instance of List each time you call submitList. If you pass a List, mutate it, and then pass that same List instance again, DiffUtil is only comparing the same list to itself, so it will assume nothing has changed in the list and won't update anything. It doesn't have some sort of memory of what the List contained back when you first submitted it.

To generalize further, you must not use a mutable List with ListAdapter at all. ListAdapter assumes the list you pass to submitList does not change. If you mutate it, there can be unexpected bugs.

Two ways to resolve this in your code.

  1. Create a read-only copy of the list each time you pass it:

    intAdapter.submitList(list.toList())

  2. Don't use a MutableList at all. Create a new List every time you modify what should be in the List. This is the simpler, less error-prone solution.

class MainActivity : AppCompatActivity() {

    private var list = listOf(1, 2, 3, 4, 5, 6, 7, 8, 9)
    private lateinit var binding: ActivityMainBinding
    var i = 0

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)
        Log.e("List", " $list")
        val intAdapter = IntAdapter()
        binding.recylerview.adapter = intAdapter
        intAdapter.submitList(list)
        binding.button.setOnClickListener {
            list += ++i // create a new list from old list contents plus a new item
            intAdapter.submitList(list)
        }
    }
}

Side note: when you have var combined with Mutable____ that should be kind of a red flag. It should be rare that you need two different ways to change something. That is error-prone.

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

DiffUtil Not working in nested recyclerview Kotlin

Kotlin when with multiple values not working when value is an android view

Kotlin android development diffutil itemCallback type error

Android Kotlin: Translate animation on view is not working

getting an error while updating value for text view android kotlin

DiffUtil is not updating the RecyclerView

Android margins not working when the view was added dynamically

android: spinner not updating my view when notifyDataSetChanged() is called

Android recycler view not updating when I click button

Renaming item with DiffUtil not updating RecyclerView

View not updating when adding new data from Room database in kotlin and compose

DiffUtil in Xamarin.Android

Kotlin crashes on Android when selected item view is null

How to refer to the button view when clicked on in android(Kotlin)?

Android kotlin - app stopps working when gallery selection is cancelled

When expression not working with enum class in onCreateDrawableState - android, kotlin

updating object with spring data mongodb and kotlin is not working

Updating UI when working with OperationQueue

javascript not working when updating the panel

Data not updating in Android view pager

Android Parcelable for Kotlin is not working

GirdLayoutManager not working, kotlin, android

Android BindingConversion not working in kotlin?

View is not updating when view model updates

java.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid view holder adapter when using DiffUtil

Ripple effect not working when clicking inside view elements (Android Appcelerator)

DiffUtil - How to keep the old List before updating it

View setBackgroundColor not working android

when(view) vs. switch(view.getId()) with Kotlin Android Extensions