I have some problems understanding RecyclerView
s SortedList
.
Lets say I have a very simple class only having a very simple class holding data:
public class Pojo {
public final int id;
public final char aChar;
public Pojo(int id, char aChar) {
this.id = id;
this.aChar = aChar;
}
@Override
public String toString() {
return "Pojo[" + "id=" + id
+ ",aChar=" + aChar
+ "]";
}
}
My understanding is that the sorted list won't contain any duplicates.
But when I have a SortedList with callbacks like this:
....
@Override
public boolean areContentsTheSame(Pojo oldItem, Pojo newItem) {
return oldItem.aChar == newItem.aChar;
}
@Override
public int compare(Pojo o1, Pojo o2) {
return Character.compare(o1.aChar, o2.aChar);
}
@Override
public boolean areItemsTheSame(Pojo item1, Pojo item2) {
return item1.id == item2.id;
}
I end up with duplicates when I add multiple items with the same id but different chars.
sortedList.add(new Pojo(1, 'a'));
sortedList.add(new Pojo(1, 'b'));
I would expect the list to update the item. Instead now I have multiple items even though areItemsTheSame
returned true
.
The SortedSet<T> class does not accept duplicate elements. If item is already in the set, this method returns false and does not throw an exception.
Java: Sorted collection which allows duplicates, is memory efficient and provides fast insert + update.
As Minhtdh already mentioned in his answer, the problem lies within your compare()
.
See, add()
looks up the existing object's index by using the compare()
you implement. Therefore when your compare()
returns something other than 0 it adds the object to the list.
You would need to check if the items are the same before comparing it's contents. However, if your content can be the same you would need a secondary comparison.
This is how I would implement the compare()
in your case:
@Override
public int compare(Pojo o1, Pojo o2) {
int result;
if (areItemsTheSame(o1, o2) {
result = 0;
} else {
result = Character.compare(o1.aChar, o2.aChar);
if (result == 0) {
// TODO implement a secondary comparison
}
}
return result;
}
SortedList does not keep any mapping by ids (because there are no ids in the API). So when the sorting criteria changes (a to b in your case), SortedList cannot find the existing element.
You can keep the id mapping yourself, then have your add method as follows:
void add(Item t) {
Item existing = idMap.get(t.id);
if (existing == null) {
sortedList.add(t);
} else {
sortedList.updateItemAt(sortedList.indexOf(existing), t);
}
idMap.put(t.id, t);
}
You'll also need to implement a remove method to remove the item from the idMap.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With