ListAdapter not updating item in RecyclerView
Edit: I understand why this happens that wasn't my point. My point is that it at least needs to give a warning or call the notifyDataSetChanged()
function. Because apparently I am calling the submitList(...)
function for a reason. I am pretty sure people are trying to figure out what went wrong for hours until they figure out the submitList() ignores silently the call.
This is because of Google
s weird logic. So if you pass the same list to the adapter it does not even call the DiffUtil
.
public void submitList(final List<T> newList) {
if (newList == mList) {
// nothing to do
return;
}
....
}
I really don't understand the whole point of this ListAdapter
if it can't handle changes on the same list. If you want to change the items on the list you pass to the ListAdapter
and see the changes then either you need to create a deep copy of the list or you need to use regular RecyclerView
with your own DiffUtill
class.
ListAdapter submitList not updating
ListAdapter doesn’t work with mutable lists. This is because if you modify the contents of the List, when it tries to compare the contents of the old list and new list, it’s comparing the same list to itself. There is no old list instance that still holds the old contents, so it cannot detect any differences.
Instead of mutating the original list, you should create a new one, for example
movieList = movieList + it.movieList
adapter.submitList(movieList)
Alternatively, you can use a mutable backing list, but always create a copy when passing it to submitList
. You must use a copy even the very first time you pass the List so it is never referring to your mutable List.
movieList.addAll(it.movieList)
adapter.submitList(movieList.toList())
List Adapter Diff Util not updating the List Item in Recyclerview
First of, the implementation of areContentsTheSame
and areItemsTheSame
probably needs to be switched. areContentsTheSame
is the one that checks if things in your items are different. areItemsTheSame
is about whether it is the same item. If the items have an id you might want to compare them instead of the item themselves. But that alone probably won't fix your issue.
The thing is, ListAdapter works best if the list has items that are immutable. Ideally you want to submit a new list every time you call submitList
. Because if you change a property like isSelected
in the existing lisk and simply call submitList with that same list nothing will happen.
So what you want to do is instead of changing the isSelected
property you need to create a copy of the list and in that copy alone you change the isSelected
and pass the copy to submitList
.
This can be tedious to make. An alternative ugly workaround that might work is to add a second property maybe called oldIsSelected
and only change that one in the DiffUtil itself, like this
override fun areContentsTheSame(oldItem: CategoryModel, newItem: CategoryModel): Boolean {
val result = oldItem.oldIsSelected == newItem.isSelected
newItem.oldIsSelected = newItem.isSelected
return result
}
ListAdapter does not update indices (positions) of the items in the RecyclerView after deleting an item
The problem lies in the onBindViewHolder
method of the NoteAdapter.
The change that resolves the issue is changing the usage of the parameter position
to holder.absoluteAdapterPosition
because according to the documentation:
Sometimes, you may need to get the exact adapter position to do some actions in response to user events. In that case, you should use this method which will calculate the Adapter position of the ViewHolder.
The modified and correct code from the question now looks like this:
override fun onBindViewHolder(holder: NoteHolder, position: Int) {
val currentNote: Note = getItem(holder.absoluteAdapterPosition)
holder.noteTitle.text = currentNote.title
holder.noteDescription.text = currentNote.description
holder.noteOptions.setOnClickListener {
optionsMenuClickListener.onOptionsMenuClicked(holder.absoluteAdapterPosition)
}
}
ListAdapter not refreshing RecyclerView if I submit the same list with different item order
Instead of
submitList(mySameOldListThatIModified)
You have to submit a new list like this:
ArrayList newList = new ArrayList(oldList);
newList.add(somethingNew); // Or sort or do whatever you want
submitList(newList);
It's kind of a problem with the API. We would expect ListAdapter to keep a copy of the list, but it doesn't, probably for memory reasons. When you change your old list, you are actually changing the same list that ListAdapter has stored. When ListAdapter checks if (newList != this.mList)
both newList
and mList
are referring to the same list instance, so no matter what you have changed on that list, it will equal itself, and ignore your update.
In kotlin you can create a new list via:
val newList = oldList.toMutableList() // Unintuitive way to copy a list
newList[0] = newList[0].copy(isFavourite = false) // Do whatever modifications you want
submitList(newList)
Note that you cannot do this:
newList.first().isFavourite = false
because that will also change the first item in your old list, and again ListAdapter
won't see a difference between the first item in your old list and the first item in your new list. I would recommend that all items in your list have val
properties exclusively, to avoid this problem.
Items in Recyclerview + Listadapter won't redraw on update
It seems to me that your data is updating but the RecyclerView is only updating the order and not the item's view. Try calling your adapter's notifyDataSetChanged()
after you update an item in your view.
Renaming item with DiffUtil not updating RecyclerView
I see that you are setting pixelArt.title
, which means your PixelArt class is mutable (has var
properties or val
properties that reference mutable classes). DiffUtil is 100% incompatible with mutable classes, because they make it impossible to compare items in the old and new lists. It will see the old list as having the new value already so it will treat it as unchanged.
Example with my imagined version of your PixelArt class.
data class PixelArt(
val objId: Long,
val name: String,
val starred: Boolean,
val imageFilePath: String
)
// In ViewModel:
// You probably have the list backed up to disk somehow. I'm just using
// placeholder functions to represent working with the repo or files or
// whatever you use.
val pixelArtLiveData = MutableLiveData<List<PixelArt>>().also {
viewModelScope.launch { it.value = readThePersistedData() }
}
private fun modifyItem(oldItem: PixelArt, newItem: PixelArt) {
pixelArtLiveData.value = pixelArtLiveData.value.orEmpty()
.map { if (it == oldItem) newItem else it }
// also update your persisted data here
}
fun renameItem(originalItem: PixelArt, newName: String) {
modifyItem(originalItem, originalItem.copy(name = newName))
}
fun toggleItemStarred(originalItem: PixelArt) {
modifyItem(originalItem, originalItem.copy(starred = !originalItem.starred))
}
// etc. or you could just make modifyItem public instead of making
// all these helper functions
Then in your adapter, you must call through to these ViewModel functions instead of directly modifying the items or the list or calling submitList
. Since the adapter doesn't have direct access to the ViewModel, you probably use your RecentCreationsListener for this by adding
appropriate actions to it that your various click listeners can call.
Your Activity or Fragment would observe this LiveData and simply call submitList()
with the observed value.
Related Topics
Googleservice Failed to Initialize
Slowing Speed of Viewpager Controller in Android
How to Build an Executable for Android Shell
Firebase Analytics Custom Events Params
Appcompat V7 R21 Returning Error in Values.Xml
Android: Accessing Assets Folder SQLite Database File with .Sqlite Extension
Android Asynctask Threads Limits
How to Use the Simple Http Client in Android
Android Recyclerview VS Listview with Viewholder
Finish an Activity from Another Activity
Don't Reload Application When Orientation Changes
Passing Arraylist Through Intent
How to Change the Text Color of Menu Item in Android
Use Picasso to Get a Callback with a Bitmap
How to Prevent an Android Device from Going to Sleep Programmatically
How to Pass Arraylist of Objects from One to Another Activity Using Intent in Android