2015-08-06 10 views
8

Ich habe einige Probleme zu verstehen RecyclerView s SortedList.Android: SortedList mit Duplikaten

Lets sagen, ich habe eine sehr einfache Klasse nur ein sehr einfaches Klasse Haltedaten:

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 
       + "]"; 
    } 
} 

Mein Verständnis ist, dass die sortierte Liste wird keine Duplikate enthält.

Aber wenn ich eine SortedList mit Rückrufe wie folgt aus:

.... 

@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; 
} 

ich mit Dubletten am Ende, wenn ich mehrere Artikel mit dem gleichen ID, aber unterschiedliche Zeichen hinzufügen.

sortedList.add(new Pojo(1, 'a')); 
sortedList.add(new Pojo(1, 'b')); 

Ich würde erwarten, dass die Liste das Element aktualisieren. Stattdessen habe ich jetzt mehrere Elemente, obwohl areItemsTheSametrue zurückgegeben.

+0

Liste kann Duplikate enthalten. Versuchen Sie es mit HashMap. –

+0

Aus meiner Sicht nicht ["Wenn das Element bereits in der Liste vorhanden ist und seine Sortierkriterien nicht geändert werden, wird es durch das vorhandene Element ersetzt."] (Https://developer.android.com/reference/android/support/ v7/util/SortedList.html # hinzufügen (T)). Ich brauche keine HashMap, da ich die effiziente Kopplung mit RecyclerView benötige. –

+0

Warum wird diese Frage mit einem Java-Tag versehen? – Boris

Antwort

-1

In Java ist eine Sammlung, die keine doppelten Elemente enthält, Set. Die gemeinsamen Implementierungsklassen sind HashSet und TreeSet. Sie irren sich, wenn Sie davon ausgehen, dass SortedList das tut.

+0

Aber tut nicht [this] (https://developer.android.com/reference/android/support/v7/util/SortedList.html#add (T)) implizieren das? –

+0

Ja, es sieht für mich verwirrend aus. Normalerweise kann List Duplikate enthalten, aber Set nicht. Können Sie versuchen, SortedSet anstelle von SortedList zu verwenden? – Boris

+1

Es ist ein Android SortedList, nicht utils.java. Es gibt kein SortedSet für die Bindung mit recyclerview. –

0

Ich denke, Sie sollten Integer.compare(o1.id, o2.id); in compare Methode verwenden, ist es, wo SortList entscheiden, dass diese 2 Elemente identisch sind oder nicht.

+1

Aus dem Dokument sagt es klar, dass das für die Bestellung ist. Und ich würde denken, dass, wenn > 2 Elemente identisch sind oder nicht ist in 'areItemsTheSame()' –

+0

Nun, ich denke, diese 2 Methode 'compare' und' areItemsTheSame' wie 'hashCode' und' gleich ', wenn Sie wollen, dass 2 Objekte die gleiche Identität haben, müssen sie zuerst denselben 'hashCode' haben, dann wird' equal' return true. In diesem Fall muss "compare" == 0 zuerst kommen, dann ist "areItemsTheSame" später wahr. – Minhtdh

8

SortedList behält keine Zuordnung durch IDs bei (da es keine IDs in der API gibt). Wenn sich das Sortierkriterium also ändert (a bis b in Ihrem Fall), kann SortedList das vorhandene Element nicht finden.

Sie können die ID halten Sie sich abbildet, dann add-Methode haben, wie folgt:

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); 
} 

Sie brauchen auch eine remove-Methode zu implementieren, das Element aus dem idMap zu entfernen.

+1

Diese Antwort sollte akzeptiert werden. – Ari

+0

Wie Sie bereits erwähnt haben, kann SortedList das existierende Element nicht finden, wenn sich die Sortierkriterien geändert haben. Wie könnte 'indexOf' den richtigen Index herausfinden? In meinem Fall gibt es immer "-1" zurück. – Shaw

+0

müssen Sie es vor dem Ändern der Daten aufrufen. – yigit

2

Wie Minhtdh bereits in seiner Antwort erwähnt, liegt das Problem in Ihrer compare().

Siehe, add() sucht den Index des vorhandenen Objekts mithilfe der compare(), die Sie implementieren. Wenn Ihr compare() also etwas anderes als 0 zurückgibt, fügt das Objekt der Liste hinzu.

Sie müssen überprüfen, ob die Elemente identisch sind, bevor Sie den Inhalt vergleichen. Wenn Ihr Inhalt jedoch gleich sein kann, benötigen Sie einen sekundären Vergleich. Diese

ist, wie ich die compare() in Ihrem Fall implementieren würde:

@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; 
} 
0

Sie können überprüfen, ob das Objekt bereits in der sortierten Liste existieren indem Sie diese.

if (sortedList.indexOf(item) == -1) 
{ 
    sortedList.add(item); //Item still does not exist because index is -1 
} 
else 
{ 
    sortedList.updateItemAt(sortedList.indexOf(item), item); 
}