2015-08-06 2 views
8

У меня есть проблемы с пониманием RecyclerView s SortedList.Android: SortedList с дубликатами

Допустит, у меня есть очень простой класс только с очень простыми данными класса удерживающими:

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

Я понимаю, что отсортированный список не будет содержать никаких дубликатов.

Но когда у меня есть SortedList с обратными вызовами, как это:

.... 

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

Я в конечном итоге с дубликатами, когда я добавить несколько элементов с одинаковыми идентификаторами, но разных символов.

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

Я ожидал бы, что список будет обновлен. Вместо этого теперь у меня есть несколько элементов, хотя areItemsTheSame вернулся true.

+0

В списке могут быть дубликаты. Попробуйте использовать hashMap. –

+0

Из моего понимания не ["Если элемент уже существует в списке и его критерии сортировки не изменены, он заменяется на существующий элемент."] (Https://developer.android.com/reference/android/support/ v7/Util/SortedList.html # Add (T)). Мне не нужен HashMap, поскольку мне нужна эффективная связь с RecyclerView. –

+0

Почему этот вопрос отмечен тегом Java? – Boris

ответ

-1

В Java коллекция, которая не содержит повторяющихся элементов, является Set. Общие классы реализации: HashSet и TreeSet. Вы ошибаетесь, полагая, что SortedList делает это.

+0

Но не [this] (https://developer.android.com/reference/android/support/v7/util/SortedList.html#add (T)) подразумевает, что? –

+0

Да, это выглядит запутанным для меня. Обычно список может содержать дубликаты, но не устанавливать. Можете ли вы попытаться использовать SortedSet вместо SortedList? – Boris

+1

Его андроид SortedList, а не utils.java. Для привязки с recyclerview не существует SortedSet. –

0

Я думаю, вы должны использовать Integer.compare(o1.id, o2.id); в методе compare, там, где SortList решил, что эти 2 элемента одинаковы или нет.

+1

Из документа ясно сказано, что это для заказа. И я бы подумал, что если > 2 элемента одинаковы или нет, в решении 'areItemsTheSame()' –

+0

. Ну, я думаю, что эти 2 метода 'compare' и' areItemsTheSame' похожи на 'hashCode' и' equal', если вы хотите, чтобы 2 объекта имели одинаковый идентификатор, они должны иметь один и тот же 'hashCode', а затем' equal' return true. Таким образом, в этом случае сначала нужно выполнить 'сравнение' == 0, а затем' areItemsTheSame' - true. – Minhtdh

8

SortedList не сохраняет отображение с помощью идентификаторов (поскольку в API нет идентификаторов). Поэтому, когда критерии сортировки изменяются (от a до b в вашем случае), SortedList не может найти существующий элемент.

Вы можете сохранить идентификатор отображения себя, то есть свой метод добавления следующим образом:

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

Вам также необходимо реализовать метод удалить, чтобы удалить элемент из IDMAP.

+1

Этот ответ должен быть принят. – Ari

+0

Как вы указали, когда критерии сортировки изменились, SortedList не может найти существующий элемент, как «indexOf» может найти правильный индекс? В моем случае он всегда возвращает '-1'. – Shaw

+0

вам нужно называть это «до» изменения данных. – yigit

2

Как уже упоминалось в его ответе Minhtdh, проблема заключается в вашем compare().

См., add(), просматривает индекс существующего объекта, используя compare(), который вы реализуете. Поэтому, когда ваш compare() возвращает что-то отличное от 0, он добавляет объект в список.

Вам нужно будет проверить, совпадают ли элементы перед сравнением содержимого. Однако, если ваш контент может быть одним и тем же, вам потребуется вторичное сравнение.

Это, как я бы реализовать compare() в вашем случае:

@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

Вы можете проверить, если объект уже существует в отсортированном списке, делая это.

if (sortedList.indexOf(item) == -1) 
{ 
    sortedList.add(item); //Item still does not exist because index is -1 
} 
else 
{ 
    sortedList.updateItemAt(sortedList.indexOf(item), item); 
} 
Смежные вопросы