Listadapter Not Updating Item in Recyclerview

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 Googles 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



Leave a reply



Submit